2024.1

1. P3780 [SDOI2017] 苹果树

首先要转化一下 \(t-h\le k\) 这个限制,考虑它的实际意义,就是我们取出所选的点中最深的一个,记为 \(x\) ,从根到它每个点都能免费领一个苹果。那我们反过来枚举 \(x\) ,尝试计算答案。按普通的方式进行 树形 dp 是 \(O(nk^2)\) 的,瓶颈在于我们合并两个背包时要 \(O(k^2)\) 地枚举。考虑换一种 dp。我们记 \(f_{x,j}\) 表示考虑了所有 \(dfn_u\le dfn_x\) 的点 \(u\) 得到的背包,其中根到 \(x\) 的点只能取 \(a_u-1\) 个。再计算 \(g_{x,j}\) 表示考虑了所有 \(dfn_u\geq dfn_x\) 的点 \(u\) 的得到的背包,其中根到 \(x\) 的点都不能取。统计答案时合并 \(f_x,g_x\) 即可。我们只关心 \(k\) 这一单点的值,所以合并是 \(O(k)\) 的。

现在的问题就是计算 \(f,g\) 。以 \(f\) 为例,我们记 \(f'_{x,j}\) 表示:考虑了 \(dfn_u<dfn_x+sz_x\) 的点,其中 \(fa_x\) 到根只能取 \(a_u-1\) 个,且 \(x\) 必取的背包。

那我们的转移是这样进行的:初始使 \(f'_x:=f_x\) 。依次遍历 \(x\) 的儿子 \(v\)\(f_v:=f'_x+\{a_v-1个苹果\},dfs(v),f'_x:=\max(f'_x,f'_v)\)

遍历完儿子之后,再在 \(x\) 强制取一个苹果,即 \(f'_{x,i}:=f'_{x,i-1}+z_x\)

考虑设计到的操作,对应取 max 是容易的;合并 \(f'_x\)\(a_v-1\) 个苹果,相当于是做一个 \(G_x=xk+\max\limits_{x-y<a_v}F_y-yk\) ,单调队列即可。

总复杂度 \(O(nk)\)

这个 trick 做树上依赖性背包非常有用。

2. gym103860D Tree Partition

\(O(nk\log n)\) 是容易的:思考 \([l,r]\) 内的点形成一个联通块的条件:边-点=-1。

我们维护 \(c_l =[l,r]内的边数 +l\) ,则这个等于 \(边-点-(r-1)\) 。支持区间加,查询全局最大值的信息即可。

但是该题存在 \(O(nk+n\log n)\) 的做法:

考虑连边 \(0-1\) ,以 \(0\) 为根把边定向,让边全都指向 \(0\)。这样的话 \([l,r]\) 形成联通块的条件就是只有一条出边。

仍然是枚举 \(r\) 并考虑哪些 \(l\) 是合法的。把边 \(u\rightarrow v\) 分成两种:\(u<v\)\(u>v\) 。对于一类边,我们找到 \(u\le r<v\) 的边中 \(u\) 最大和次大的,分别记为 \(x_1,x_2\) 。则对于 \(l\in [x_1+1,r]\) ,我们要求只能有一条二类边;对于 \(l\in [x_2+1,x_1]\) ,不能有二类边。

现在考虑记 \(c_l\) 表示当前 \([l,r]\) 往外的二类边个数。则每次从 \(r-1\) 更新到 \(r\) 时,对于 \(u=r\) 的二类边,我们有 \(l\in (v,r]\)\(c_l\) 都 +1。于是我们维护两个栈,分别记下 \(c_l=0\)\(c_l=1\) 的位置,同时维护 dp 数组的前缀和。每次修改相当于是若干次弹栈,入栈操作,而每个点至多会被修改两次,所以是均摊 \(O(1)\) 的。

\(x_1,x_2\) 用 set 计算即可。复杂度 \(O(n\log n+nk)\)

3. gym103640D Daily Turnovers

先转化问题。为了方便,将所有变化取反。

计算前缀和 \(s_l\) 后,我们相当于对 \(l\in [0,n]\) ,求出 \(R_l\) 表示 \(l\) 右边第一个大于它的数,统计 \(\sum R_l\) ,再减掉 \(\tbinom{n+2}{2}\) 即可(设 \(s_{n+1}=+\infty\))。

现在考虑操作:在 \(p\) 上单点加 \(x\) ,反映到前缀和上就是后缀加 \(x\) 。思考哪些 \(R\) 会发生变化:维护 \([0,p)\) 的单调栈,则只有单调栈中的点的 \(R_i\) 会变化。再维护 \([p,n+1]\) 的单调栈,则变化了的 \(R_i\) 只可能变成这个栈中的点。具体的,令 \(F(j)\) 是前面的栈中 \(s_i\le j\) 的数个数,令 \(s'_i=s_i+x-1\)\(A\) 表示后面的栈,则减去会变化的 \(R_i\) ,再加上 \(\sum\limits_{i=1}^{top}A_i(F(s'_{A_i})-F(s'_{A_{i+1}}))\) 即可。

维护 BIT 以计算 \(F\) 。每次 \(p\) 改成 \(p+1\) 时,两个栈都有均摊 \(O(1)\) 次修改,对前一个栈修改是容易的: 加入 \(i\) 时,维护好 BIT,再找到最小的 \(s'_p\ge s_i\) ,让总和加上 \(p\) 。对后一个栈修改,就是加入一个数 \(x\) 时它一定是栈顶,我们加上 \((x-A_{top})F(s'_x)\) 即可。删除也是类似的,总复杂度 \(O(n\log n)\)

4. gym101309J Jungle Outpost

二分答案,做 \(p_i\rightarrow p_{i+mid}\) 的半平面交,看是否为空即可。

5. gym100520K Kabbalah for Two

判圆在凸包->判凸包往内缩了 \(R\) 之后,点是否在凸包内。

那我们二分答案之后,为了取的两个圆相离且在凸包内,就先求出往内缩 \(mid\) 后的凸包,再用旋转卡壳求最远点对,看距离是否 \(\geq 2mid\) 即可。

6. gym102896G Geometrical Combinatorics

直接计算困难,考虑将整个坐标系转 90 度并往内缩一下,杨辉三角就都在第一象限内了,也就是说 \((i,j)\) 处放的是 \(\tbinom{i+j}{i}\) 。那枚举 \(x\) 坐标,求 \(x=a\) 和三角形的交点,问题就转化成上指标求和。

7. P6925 [ICPC2016 WF] Spin Doctor

先转化成:求出 \(t_i=1\) 的点构成的凸包,取一个方向,用两条线卡住凸包,看中间有多少 \(t_i=0\) 的点。反过来看 \(t_i=0\) 的点在哪些时候不会有贡献:首先在凸包内肯定寄了;否则,求出对凸包的两条切线,则方向要取在这两个之间才不会有贡献。最后离散化,差分搞搞就能算出答案了。

问题是怎么求点对凸包的切线:如果点的横坐标比凸包上所有点都小或者大,那么可以把上下凸壳中分别二分。否则可以按照这个点的横坐标把凸包分成左右两半,再在两半中分别二分即可。(By Kubic)

8. gym102576D Clique

先思考不是环怎么做,显然需要所选区间的交非空,那我们一定是枚举一个点 \(x\),取所有 \(l\le x\le r\) 的区间。那现在是环了,仍然是枚举中间的一个点 \(x\),要求不包含 \(0\) 的区间都包含 \(x\) 。于是我们只需考虑跨过 \(0\) 和跨过 \(x\) 的区间。不难转化成:你有一些黑点和白点,然后要取一些点,让黑点右上角没有白点。从左往右取黑点,在 dp 状态记下来当前最低的黑点,那能取的白点个数就能顺便得到了。再用线段树优化这个 dp 即可。

9. gym103415B Sweeping Robots

对每次询问,取出 \([l,r]\)\(c\) 最小的位置 \(k\) ,拆成 \([l,k)\)\((k,r]\)

那就转化成了对笛卡尔树某个节点代表区间的某个前缀/后缀求答案。

前缀为例。现在对于点 \(x\) ,先求出 \(ls_x,rs_x\) 的结果,合并一下。然后考虑跨过 \(x\) 且在范围内的区间。那 \(l\) 端点是固定的;根据 \(s_r-s_x\)\(s_x-s_l\) 的大小关系把 \(r\) 分成两个线段,每个线段中 \(r\) 的权值都能写成 \(ks_r+b\) 。那尝试用李超树维护这个东西。插入线段是容易的,关键是我们能否合并?发现也是可以的,因为两个子树的 \(s_x\) 是不交的。但查询时是前缀 max,于是和以往不同,我们还需要在李超树的每个节点记下来子树内的最大权值。

upd:似乎并不需要合并线段树。

复杂度 \(O(n\log^2n+q\log n)\)

10. gym102879J Japanese Knowledge

啊?有结论:恰好 \(k\) 个位置满足 \(x_i=a_i\) 的答案等于:\(a_{k+1},a_{k+2},\ldots,a_n\)\(k=0\) 时的答案,构造双射易得。然后格路计数一下就好了。复杂度 \(O(n\log^2n)\)

11. P5853 [USACO19DEC] Tree Depth P

\(i\)\(j\) 在笛卡尔树上的祖先,等同于 \(\max(a_i,\ldots,a_j)=a_i\) 。考虑算逆序对的过程,就是我们一个个插入数,第 \(i\) 个数对逆序对的贡献是 \(0\)\(i-1\) 。你发现我们不止能每次从末尾插一个数,从前面插也是可以的,而且贡献是没有区别的。

现在不妨令 \(j<i\) ,我们就先插入 \(j+1\)\(i\) ,再插入 \(j\) ,再插入剩下的数即可。你发现预处理前后缀的数组拼起来即可,复杂度 \(O(n^3)\)

12. P5044 [IOI2018] meetings 会议

省流版题意是令 \(f(x,y)\)\(\min(x,y)\)\(\max(x,y)\)\(h_i\)\(\max\) 值,然后每次询问要取一个点 \(x\) 使得 \(\sum\limits_{i=l}^r f(i,x)\) 尽量小。

考虑 \(l=1,r=n\) 的做法,就是建出笛卡尔树 dp ,我们有 \(dp_x=\min(dp_{ls}+h_x(sz_{rs}+1),dp_{rs}+h_x(sz_{ls}+1))\)

那现在还是建出全局的笛卡尔树,然后考虑先找到 \(l,r\)\(lca\)\(t\) ,拆成 \((t,r],[l,t)\) 分别询问再拼起来。那现在要考虑的区间一定是一个节点代表区间的前缀/后缀。

以前缀为例,我们从下往上计算,令 \(f(x,y)\) 表示 \([L_x,y]\) 的答案,你发现对于 \(y<x\)\(f(x,y)=f(ls_x,y)\) ,对于 \(y\geq x\)\(f(x,y)=\min(yk+b,f(rs_x,y)+t)\) ,其中 \(k,b,t\) 是可以计算出的三个常数。那我们就完全让 \(f(x)\) 直接继承子树的信息,即直接用数组 \(g_y\) 记下当前 \(f(x,y)\) 的值。现在涉及到的操作就是区间加和区间对 \(kx+b\)\(\min\) ,看似需要高级数据结构,实际上你发现,这里是满足 \(k=h_x\) 的,而容易发现 \(g_p\le g_{p-1}+k\) 。所以 \(yk+b\le g_y+t\)\(y\) 一定是一段前缀!于是线段树二分找出分界点后,直接打覆盖 tag 即可。复杂度 \(O(n\log n)\)

13. CF1718D Permutation for Burenka

判定 \(a\) 合法:建出的笛卡尔树与给定排列 \(p\) 的笛卡尔树相同。

那首先我们可以对每个 \(a_i=0\) 的点求出它能填的数的上下界:上界是它最近的已填祖先的 \(a_x-1\) ;下界是它子树中已填的最大 \(a_x+1\) 。你发现如果保证上下界了之后,乱填也能调整成合法的,因为如果出现一对 \(a_x<a_v\) ,那由于我们已经限制了空位和已填位之间的关系, \(x\)\(v\) 一定原来都是空位。然后你发现交换它们俩一定是不会破界的,第一 \(R_x=R_v\),第二 \(L_x\geq L_v\) ,调整后更容易满足。

现在就是有一些区间和一些点,区间要和点做匹配,区间要包含点才能匹配上。

可以贪心的做,就是从把区间按 \(r\) 排序后,每次取在区间内的最小点即可。

但现在点集里有一个是不固定的,怎么办呢。

我们仍然搞一遍原来的贪心,然后会出现一个区间,它内部匹配不上点。此时我们就一定需要 \(d\le r\) 。再往后若又有一个不合法区间,肯定就寄了,因为 \(d\) 只能满足前一个区间,扫到这里就还是不合法了。

倒着扫一遍又可以得到 \(d\) 的下界,这两个界就是充分的了。证明比较复杂。

复杂度 \(O(n\log n+q)\) ,瓶颈在于贪心时找区间内最小点。

14. qoj2570 Maximal Subsequence

\(f_i\) 是以 \(i\) 为结尾的最长上升子序列,则我们能建出最小割:若 \(i<j,a_i<a_j\)\(f_i+1=f_j\) 则连边 \((i+n,j,+\infty)\)\(f_i=1\) 则连边 \((S,i,+\infty)\)\(f_i=\max f_j\) 则连边 \((i+n,T,+\infty)\) 。再连边 \((i,i+n,1)\) 。最小割=最大流,发现问题转化成:在序列中取尽量多的 LIS。这等于杨表最后一列的长度,可以 \(O(n\sqrt{n}log n)\) ;但事实上能直接模拟这个流的过程,可以证明我们先尝试流编号更小的点就不会退流。具体就是走到 \(u\) 时先弹掉下一层 \(<u\) 的点;再依次枚举下一层每个点 \(v\),如果 \(a_u\geq a_v\) 就结束,否则尝试流 \(v\) ,如果 \(v\) 走不到 \(T\) 就直接删掉 \(v\) 即可,否则结束。这样就是 \(O(n\log n)\) 了,瓶颈在求 \(f\)

15. qoj5246 Nawiasowe podziały [B]

首先设 \((\)\(+1\)\()\)\(-1\) ,令 \(s_i\) 是括号权值的前缀和。

\((l,r]\) 合法等同于 \(s_l=s_r=\min\limits_{i=l}^r s_i\)

场上的想法就是,我们可以进行染色,使得合法的 \((l,r]\) 满足 \(col_l=col_r\)

先 wqs 二分,发现具有决策单调性,然后发现 \(val(l,r)\) 似乎没有办法直接求,但移动指针,\(O(1)\) 更新 \(val(l,r)\) 是容易的,于是通过分治套分治做到 \(O(n\log^2n\log V)\) 。场上就止步于此了。

原因在于我把条件强化了,事实上可以发现对于两个颜色,它们要么不交要么包含。

事实上,注意到 \(s_l=s_r=\min\limits_{i=l}^r s_i\) 是和笛卡尔树相关的,尝试建小根笛卡尔树。但普通笛卡尔树是一个点代表一个元素,这样在区间有多个最小值的时候只能随便选一个,会丢失一些信息。于是使用广义的笛卡尔树,一个点会维护这个区间所有最值的位置。

这样建之后,你发现每个颜色都对应了一个节点。那预处理欧拉序的 ST 表后, \(val(l,r)\) 就能 \(O(1)\) 求了,利用 deque+二分的手法就能做到 \(O(n\log n\log V)\)

但想优化到单 log 的话,考虑 wqs 二分基本是无法避免的,于是只能避免决策单调性。但 \(val(l,r)\) 似乎也无法直接拆成一个简单的形式供我们优化,于是想到直接进行树形 dp,设 \(dp_u\) 是在 \(u\) 内砍至少一刀,能得到的最小权值,注意这里为了方便,可以在节点的左边/右边切一刀。令 \(n_u\)\(u\) 儿子的个数。令 \(t_u\)\(u\) 子树内所有点的 \(\sum \tbinom{n_u}{2}\) 之和。

那计算当前 \(dp_u\) 的值,就先求出儿子的 dp 值。不妨令儿子的编号为 \(1,2,\dots,n_u\) ,再求出 \(s_i\) 表示儿子的 \(t_i\) 前缀和,令 \(f_i\) 为:从左往右考虑到第 \(i\) 个儿子,且儿子 \(i\) 一定被劈的最小代价,有 \(f_j=\min\limits_{i<j} f_i+\tbinom{j-i}{2}+s_{j-1}-s_i\) 。斜率优化 dp 即可。

这样总复杂度就是 \(O(n\log V)\) 的了。

16. AGC041F Histogram Rooks

考虑容斥,指定一些点不会被覆盖,我们称这些点是黑格子。还是建出笛卡尔树从下往上 dp ,但是你发现这个会出问题:如果之前某列上有一些格子还能填,结果往上走时这一列突然出现了黑格子,那这个系数就不好算了。。

那你考虑我们每次加入新的一列时就指定:这个列中是否有黑格子。这样就好算了,把子树内被指定的列数记下来计算即可。

但你发现还是有问题,因为你指定了一列有黑格子,但算到最后可能并没有黑格子,这怎么办呢。那我们再次容斥,钦定一些指定有黑格子的列其实没有黑格子。

那现在考虑计算系数,先加入中间一列,然后再在当前节点进行填充,设有 \(t\)\(x\) 列。那首先这 \(t\) 行的系数都是相同的,我们只需要计算 \(1\) 行的系数。第一个 case 是没有填黑格子,那方案数是 \(2^{x-i}\) ,其中 \(i\) 是指定有黑格子的列个数。第二个 case 是填了至少一个黑格子,方案数是 \(\sum\limits_{k=1}^{i-j}(-1)^k\tbinom{i-j}{k}=-[i=j]\) ,其中 \(j\) 是其实没有黑格子的列个数。注意到系数只和 \(i,j\) 是否相等有关,在状态中记下 \(i,[i=j]\) 即可,复杂度 \(O(n^2)\)

17. AGC336G 16 Integers

考虑把这个序列当成是一条点数为 \(n+1\) 的路径,其中第 \(i\) 个点是 \(a_ia_{i+1}a_{i+2}\) 拼成的点。 \(x_{a,b,c,d}\) 相当于是这条路径中 \(abc\)\(bcd\) 的边数。

于是问题转化成:从任意一点出发,任意一点结束,经过所有边的方案数。

我们有 BEST 定理:从 \(s\) 为起点和终点的欧拉回路个数是 \(A\prod (out_i-1)!\) ,其中 \(A\) 是以 \(s\) 为根的内向生成树个数。

回到这个题上,有两种可能的情况:第一种是所有点都满足出边=入边,那枚举起点,直接套 BEST 定理即可;第二种是有个点 \(x\) 满足出边=入边+1,另一个点 \(y\) 满足入边=出边+1,剩下的平衡,那建一个虚点 \(s\) 并连边 \((s,x),(y,s)\) ,再用 BEST 定理计算从 \(s\) 出发的回路个数即可。

注意最后要除以 \(\prod x_{a,b,c,d}!\) ,因为上面的计算过程把一些相同的边当成不同的了。

\(N=2^k\) ,时间复杂度 \(O((\sum x_{a,b,c,d})+N^4)\)\(k\) 在本题中 \(=3\) 。上面是我赛时的做法。

考虑优化:第一,我们在第一种情况中无需枚举起点,我们先挖掉一条边变成第二种,再让答案乘上 \(n\) 即可。这样就是 \(O(N^3)\) 的,可以开到 \(k=8/9\) 了 。

第二,考虑加快行列式的计算,注意到我们的矩阵中只有 \(O(N)\) 个位置是非零的 ,考虑以此优化计算。我们知道矩阵的特征多项式是 \(f(x)=|Ix-A|\) 。那么若能求出这个特征多项式, \((-1)^Nf(0)\) 就是想要的答案。但是怎么计算特征多项式呢?不好计算。但现在,假设我们能快速求出矩阵的最小多项式。

如果最小多项式项数 \(=N\) ,说明这就是特征多项式;否则随机一个对角矩阵 \(D\) ,有结论:\(AD\) 的最小多项式项数大概率 \(=N\) 。计算 \(\frac{det(AD)}{det(D)}\) 即可。

现在问题变成计算最小多项式。我们要知道,如果已知最小多项式 \(\le n\) ,那通过序列的前 \(2n\) 项即可唯一确定最小多项式。我们分三步进行:

  1. 算序列 \(a\) 的最小多项式,即找到 \(c_i\) 使得对任意 \(x\)\(\sum c_ia_{x+i}=0\) 。使用 Berlekamp-Massey 算法即可做到 \(O(n^2)\)

  2. 算一组向量 \(b\) 的最小多项式,其中向量有 \(m\) 维。结论:随机 \(m\) 维向量 \(u\) ,找到序列 \(p_i=u^Tb_i\) 的最小多项式即可。复杂度 \(O(n(n+m))\)

  3. 算矩阵 \(A\) 的最小多项式。仍然是随机 \(n\) 维向量 \(u\) ,令 \(b_i=A^iu\) 。再找到 \(b\) 的最小多项式即可。复杂度 \(O(n(n+T))\) ,瓶颈在于算 \(b\) ,我们要进行 \(n\) 次向量乘矩阵的操作。其中 \(T\)\(A\) 中非零元素的个数。

结合上面的步骤,我们得到 \(det(A)\) 可以在 \(O(n(n+T))\) 的时间求出。于是原题可以优化到 \(O(N^2)\) 的复杂度!可以开到 \(k=12/13\)

18. P6929 [ICPC2017 WF] Airport Construction

思路不难,就是我们选取的线段一定穿过了至少两个顶点。\(O(n^2)\) 枚举两个端点得到一条直线,然后找到多边形所有边和这条直线的交点,把直线拆成 \(O(n)\) 段,判断每段是否合法即可。

但代码实现很有技巧:对于多边形的一条边,它影响这条直线有两种可能:第一,一个端点恰好在线上,另一个不在。根据方向,我们把这个交点的权值设为 \(1/-1\) ;否则,若这条边和直线严格相交,则把交点的权值设为 \(2/-2\) 。处理完后从左往右扫这个直线,看当前权值的前缀和是否等于0,即可判断当前这一段是否还在多边形内了,它的巧妙之处就在于,考虑 \(A_iA_{i+1}A_{i+2}\) ,若 \(A_{i+1}\) 在线上,则:若 \(A_i,A_{i+2}\) 在同侧,则 \(A_{i+1}\) 被一个 \(+1\) ,一个 \(-1\) 抵消了;若在异侧,则根据方向会变成 \(+2/-2\) ,这就和严格相交的情况相同了。这就避免了复杂的讨论。

19. P9265 [PA 2022] Chodzenie po linie

首先排除掉无解的部分,根据 \(p_{1}\)\(p_x\) 重排后是否为 \([1,x]\) ,把排列分成若干段分别处理即可。

考虑手玩一下 bfs,我们一层一层的看当前能走到那些点。第一步后 \((i,p_i)\) 的左上角右下角都走到了;而右上角和左下角是互不影响的,于是只看左下角。令 \(a_i\)\(p\) 的后缀 min ,\(b_i\)\(p_j\geq i\) 的点中最小的 \(j\) 。 你发现我们相当于是从 \((i,p_i)\) 出发,每步从 \((x,y)\) 走到 \((b_y,a_x)\) ,并沿途计算 \(S(x-1,y-1)\) 的和(\(S(x,y)=\sum\limits_{i=1}^x [i\le y]\)) 。

这样就得到了一个 \(O(n^2)\) 的做法,考虑优化。猜测经过的点数是不多的,事实上可以证明是 \(O(n\sqrt{n})\) 的,原因是你发现每条一步, 要么 \(x+y\) 减少 \(\sqrt{n}\) ,要么 \(|x-q_y|\le \sqrt{n}\) 。这样记忆化一下就是 \(O(n\sqrt{n}\log n)\) 的,瓶颈在于求 \(S\) ;事实上离线下来,用分块即可平衡至 \(O(n\sqrt{n})\)

20. 关路灯,但是 O(n)

考虑经典的 dp 状态所以只能两维是因为:如果我们走到一端,不记另一端关了多少灯,会导致重复计算。

考虑我们每一步其实是在干这样一件事:令 \(E(x)\) 表示我们认为的 \(x\) 最小可能被关的时间,则每走一步后计算 \(E(x)\) 的增量,最后 \(E(x)\) 全都固定成真实值了,也就算出答案了。传统的做法就是认为,对于还未关的灯, \(E(x)\) 等于当前的时刻 \(T\)

但我们可以这样设计:设 \(E(x)=T+|x-X|\) ,其中 \(X\) 是你现在所在的位置。

现在再看我们走的过程,比如说从起点左边的 \(i\) ,走到起点右边的 \(j\)。考察 \(E\) 的变化,你发现右端的这些点 \(E\) 无论状态如何,都是不变的!改变的只有左端未被推的点,改变量即 \(2s_{i-1}(x_j-x_i)\) ,其中 \(s\) 是功率的前缀和。

这样就容易设计 dp 了,我们只需设 \(dp_i\) 表示走到 \(i\) 时的最小势能和,输出 \(dp_1+\sum |x_c-x_i|s_i\) 即可,原因是走到 \(1\) 时即使右部灯没有关完,我们走过去关了也不影响势能。

发现可以斜率优化,最后复杂度 \(O(n)\) 。注意转移顺序,类似于 dij ,先用更小的 \(dp_i\) 来转移,具体维护两个指针即可。而且也得维护两个凸包。

21. gym104022J The Answer!

显然有 \(\gcd(a^x-1,a^y-1)=a^{\gcd(x,y)}-1\) ,而 \(\gcd(F_x,F_y)=F_{gcd(x,y)}\)

于是原问题可以转化成计算 \(\frac{a^{F_{xk}}-1}{a^{F_x}-1}\) 。模数是合数,拆成 \(\prod p^k\) 分别计算再 CRT 合并。

先分别计算分子分母,注意这里要用扩展欧拉定理处理一下 \(F_x\)\(F_{xk}\)。(\(\varphi(p^k)=(p-1)p^{k-1}\)) 。

最希望看到的是分母 \(Y\)\(p\) 互质,这样直接求逆就好了。但很多时候并不互质。考虑求出最大的 \(t\) 满足 \(p^t|Y\) ,然后我们再计算一遍分子和分母模 \(p^{k+t}\) 的结果。这样分子和分母就都是 \(p^t\) 的倍数了,同时除掉 \(p^t\) ,这样分母就和 \(p\) 互质了。

\(t\) 也有可能很大。如果 \(t\geq k\) ,我们就无法直接找出 \(t\) 了。但注意到,\(\frac{a^{F_{xk}}-1}{a^{F_x}-1}=\sum\limits_{j=0}^{\frac{F_{xk}}{F_x}-1}a^{jF_{x}}\) 。而如果 \(t\geq k\)\(a^{F_x}\) 在模意义下 \(=1\) ,于是就变成了求 \(\frac{F_{xk}}{F_x}\)

而观察发现 \(F_0,F_n,F_{2n},\dots\) 也是二阶递推,具体的有 \(F_{ni}=q_nF_{n(i-1)}+F_{n(i-2)}\) ,其中 \(q_n=q_{n-1}+q_{n-2}\)\(q_0=2,q_1=1\) 。这就做完了,复杂度瓶颈在于把模数质因数分解。

22 GDKOI

D1T1:先任意跑出一组最大匹配,然后考虑调整,调整就是在残量网络上找到一个简单环,满足黑边个数为奇数。直接在可能的环中取最小的,可以证明一定是简单环,否则能拆成两个更小的环。复杂度 \(O(nm)\)

D1T2:考虑倒着枚举操作。如果当前的操作是询问,则没有影响;如果是染色,它会使得后面的一些询问操作权值发生变化。具体的用 ODT 来维护,则我们当前会有均摊 \(O(1)\) 次操作,就是把一个区间 \([l,r]\) 的颜色从 \(col\) 变成 \(i\) ,注意这里的”颜色“是指它被染的时刻。

那对于 \(i\in [l,col-1]\) ,如果是询问操作,我们会把 \(a_i\) 加上 \(|[x,y]\cap[l_i,r_i]|\)

然后我们处理左端点是 \(i\) 的查询,就是算 \(a\) 的区间和。

施加容斥后就转化成以下问题:给定序列 \(b_i\) ,修改操作是让一个区间的 \(a_i\) 加上 \(\min(b_i,z)\) , 查询操作就是区间和。发现 poly 不能,但分块容易,复杂度 \(O(n\sqrt{n})\)

你说的对,但写出来跑 2e5 都吃力啊?内存不能开 \(O(n\sqrt{n})\) ,但对每个块依次做又会导致内存使用太分散。

D1T3:太复杂了咕咕咕。

D2T1: 列出区间合法的两个条件:\(\sum (b_i-a_i)\geq 0;E+\sum \min(b_i-a_i,0)\geq \max\limits_{i} \min(a_i,b_i)\) 。发现只靠虑第二个条件的话直接双指针,用可删堆维护当前区间中 \(\min(a,b)\)\(max\) 即可。再处理第一个条件,用 BIT 顺便维护即可。

D2T2:首先 \(\gcd(m^a-1,m^b-1)=\gcd(m^{\gcd(a,b)}-1)\) ,于是能方便地算出 \(L,R\) ,并且发现 \(m|R-L+1\) 。发现答案只和 \(T=\frac{R-L+1}{m}\) 有关。
现在要求子集和是 \(m\) 的倍数,考虑单位根反演,可以写出: \(\frac{1}{m}\sum\limits_{i=0}^{m-1}(\prod\limits_{j=0}^{m-1}w_m^{ij})^T\) 。注意到 \(\prod\limits_{i=0}^{n-1} (1+w_n^i)=1-(-1)^n\) ,于是令 \(g=\gcd(i,j)\) ,则 \(\prod\limits_{j=0}^{m-1}w_m^{ij}=(1-(-1)^{\frac{m}{g}})^g\)。转而枚举 \(g\) ,最终答案为 \(\frac{1}{m}\sum\limits_{g|m}\varphi(\frac{m}{g})(1-(-1)^{\frac{m}{g}})^{gT}\)

D2T3: 考虑二元多项式 \(T=x+x^{-1}+y+y^{-1}\)。注意此题中系数都对 \(2\) 取模,且 \(x^{2^n}=y^{2^n}=1\)

我们设计这样一个操作:把矩阵所有为 \(1\) 的位置都操作一次。那 \(A\) 就会变成 \(AT\) 。你发现 \(T^n=0\) ,于是 \(AT^n=0\) ,这就是 \(O(2^{3n})\) 的做法,直接模拟即可。

考虑快速计算答案矩阵,相当于要算 \(A\sum\limits_{i=0}^{+\infty} T^i\) 。拆成 \(A\prod (1+T^{2^i})\) 即可,因为 \(T^{2^i}=x^{2^i}+x^{-2^i}+y^{2^i}+y^{-2^i}\)

\(i\) 只需枚举到 \(n\) ,于是复杂度 \(O(n4^n)\) 。你说的对,但这是 CF1270I。

23. gym103439D LIS Counting

设计两张表,第一张表中 \(A_{i,j}\) 表示以该值为末尾, LIS 为 \(i\) ,LDS 为 \(j\)\(B_{i,j}\) 表示 \(A_{i,j}\) 的下标。 \((A,B)\) 和可能的排列仍然形成双射。只要算出 \(g_{x,y,i}\) 表示 \(A_{x,y}=i\) 的可能 \(A\) 个数 ,然后计算 \(\sum\limits_{x,y} g_{x,y,Y}g_{n+1-x,y,X}\) 即可。现在设 \(dp_{S}\) 表示我们从按值小到大给 \(A\) 的每个格子染黑,当前染黑的格子的轮廓线是 \(S\) 的方案数,算出 \(dp\) 就容易算 \(g\) 了。注意到状态数 \(\tbinom{n+m}{n}\) ,直接转移即可。复杂度 \(O(\tbinom{n+m}{m})\)

24. 0106 T3 玩图

考虑部分分:中间一段 \([kl,kr]\) 是固定的,即 \(r\geq kr,l\le kl\) 永远成立。那就开两个栈,栈中每个元素维护一些关键点在最小生成树上构成的虚树。查询把两个栈顶拼起来即可。

但可能某个时候把 \(kl\)\(kr\) 删了,怎么办呢。取尽量靠中的位置作为新的 \(kl,kr\) 重构即可。

25. gym102465G String

\(f(x,l,r)\) 是串 \(x\)\(l\) 到第 \(r\) 个字符的权值和。直接递归的计算的话发现会出问题,就是说如果串 \(x\) 是由串 \(a\) +串 \(b\) 构成的, 那这里就会递归就会出现两个分支,这样下去就是指数级了。

怎么办呢,尝试只做前缀/后缀,把 \(f(x,l,r)\) 拆成 \(f(x,l,r)=f(x,1,r)-f(x,1,l-1)\)。发现如果串 \(x\) 是两个串拼起来的,要么 \([l,r]\) 只在一个串内,要么完全包含了一个串,且另一个串也是前缀/后缀。

只需先处理出来小于 \(x\) 的串的权值即可。具体实现就是依次算,记下 \(val_x\) 即可。

但串 \(x\) 还可能是取出 \(y\) 的一个子串得到的,这怎么算呢。比如说算 \(f(x,1,a)\) ,你发现可以写成 \(f(y,1,a+pl_x-1)-f(y,1,pl_x-1)\) 。我们预处理 \(A_x=f(y,1,pl_x-1)\) 即可。\(f(x,a,sz_x)\) 同理。这样每次调用 \(f\) 都是 \(O(n)\) 计算的,复杂度 \(O(n^2)\)

26. SGU209

计算直线两两的交点,把每条直线分成若干线段。思考怎么找出每个有限区域,只需从一个线段出发,摸着墙走就好了,具体的你把交点离散化下来,把与一个点相邻的线段按极角排序,就能求出在每条线段能摸到的下一条线段了。这样走下去,直到走回起点即可。

27. 0117 T2 xor

题意是给你一个矩阵,让你求 \(\oplus_{i=1}^n a_{i,p_i}\) 有哪些可能值,\(n\le 60,a_{i,j}<2^{12}\)

确定性算法一眼不能,因为这类似于积和式,具体的我们令 \(F_{i,j}(x)=x^{a_{i,j}}\),异或就变成了做异或卷积,计算 \(\sum \prod F_{i,p_i}(x)\) 后看哪些项非零即可。

因为只是 check 非零,尝试直接改成求行列式,但这显然容易卡掉。尝试随机化算法,发现对每个 \(F_{i,j}(x)\) 乘上一个随机的系数,再求行列式就大概率正确了:原来就是 \(0\) 的显然仍是 \(0\) ,原来 \(>0\) 的只有 \(\frac{1}{mod}\) 的概率判成 \(0\)

这就做完了,我们先把每个 \(F_{i,j}\) FWT 一下,对每个点算行列式,再 IFWT 回去即可,复杂度 \(O(n^3V+V\log V)\)

28. 0117 T3

快进到 \(F_n(x)=\sum\limits_{i=0}^{kx-1}F_{n-1}(i)\) 。我们维护 \(F_n(i)\) 的系数,考虑 \(\sum\limits_{i=0}^{n-1}i^m=\frac{1}{m+1}\sum\limits_{i=1}^{m+1}\tbinom{m+1}{i}n^iB_{m+1-i}\),于是 \(f_{n,i}=k^i\sum\limits_{j=i-1}^nf_{n-1,j}\frac{j!}{i!(j+1-i)!}B_{j+1-i}\)

这是一个格路计数的形式,令 \(a_i\) 为我们走到了 \((i,a_i)\) ,则可以写出序列 \(a\) 的贡献: \(\frac{1}{a_n!}\prod\limits_{i=1}^n k^{a_i}\frac{B_{a_{i-1}+1-a_i}}{(a_{i-1}+1-a_i)!}\) 。令 \(d_i=a_{i-1}+1-a_i\)\(s=\sum d_i\) ,可以改写成 \(\frac{k^{n(n+1)/2-(n+1)s}}{(n-s)!}\prod\limits_{i=1}^n k^{id_i}\frac{B_{d_i}}{d_i!}\) ,要求对于 \(i\geq 1,\sum\limits_{j=1}^id_j<i\) 。相当于我们的路径只能在 \(y=x\) 这条直线下。就尝试容斥,钦定我们会走过哪些 \((i,i)\) ,令 \(dp_i\) 表示从起点走到 \((i,i)\) 的系数和。 令 \(G(x)=\sum\frac{B_ix^i}{i!}\) 。那只要算出 \(w_n=[x^n]\prod\limits_{i=1}^n G(k^ix)\) ,就有 \(dp_j=-\sum\limits_{i=0}^{j-1}k^{i(j-i)}w_{j-i}dp_i\)

考虑算 \(w\) 。令 \(H(x)=\ln G(x)\)\(\ln \prod\limits_{i=1}^n G(k^ix)=\sum\limits_{i=1}^n\sum\limits_{j=0}^{+\infty}h_jx^jk^{ij}=\sum\limits_{j=0}^{+\infty}h_jx^jk^j\frac{1-k^{nj}}{1-k^j}\) 。再设 \(R(x)=\sum\limits_{j=0}^{+\infty}h_jx^jk^j\frac{1}{1-k^j}\) ,则 \(w_n=[x^n]e^{R(x)}e^{-R(k^nx)}\) 。求出 \(Q,P\) 表示 \(e^{R(x)},e^{-R(x)}\) 的系数,最终可以推出 \(w_n=\sum\limits_{i=0}^nk^{ni}P_iQ_{n-i}\) ,可以 \(O(n\log n)\) 求出。

接下来考虑统计答案,需要求出 \(ans_i=\sum\limits_{j=0}^i dp_jk^{j(i-j)}[x^{i-j}]\prod \limits_{d=1}^{n-j} G(k^dx)\) 。用同样的方法即可得到上式等于 \(ans_i=\sum\limits_{j=0}^i dp_jk^{j(i-j)}\sum\limits_{d=0}^{i-j}P_dQ_{i-j-d}k^{(n-j)d}=\sum\limits_{j+u+v=i}dp_jP_uQ_vk^{nu+vj}\) 。先计算 \(f_i=\sum\limits_{j+v=i} dp_jQ_vk^{vj}\) ,再算 \(ans_i=\sum\limits_{j+u=i}f_jP_uk^{nu}\) 即可。

总复杂度 \(O(n\log n)\)

29. 0118 T3(upd:qoj4094)

先建出笛卡尔树,约定 \([l_x,r_x]\)\(x\) 代表的区间,\(k_x=r_x-l_x+1,b_x=k_xh_x\)

先看 \(k=2\) ,对于取的每个矩形,取关键点为 \([xl,xr]\)\(h\) 最小的那个。考察这两个点的位置关系,如果不是祖孙的话,直接把 \(b_x\) 加起来就好了;否则枚举祖先,需要查它子树内 \(b_x-h_fk_x\) 的最大值。排成 dfn 序,使用线段树,在每个节点建立 \([l,r]\) 构成的凸包,这样复杂度是 \(O(n\log n)\)。然后考虑 \(k=3\) ,仍然是分类讨论,发现最难的情况是一个点 \(z\) 子树内有两点 \(x,y\)\(x,y\) 没有祖孙关系,贡献为 \((b_x+b_y)+b_z-h_z(k_x+k_y)\) 。直接做是非常困难的,我们尝试以式子为核心,放宽对点的位置关系的限制,你发现 \(x\)\(z\)\(y\)\(z\) 的影响都是达到了上限的,所以我们可以把 \(z\) 放宽到任意位置,不影响答案!现在只需要 \(x,y\) 不是祖先关系。求出 \(p_a\) 代表 \(k_x+k_y=a\) 的合法点对中 \(h_x+h_y\) 的最大值即可。不妨设 \(r_x<l_y\) ,我们把 \([r_x+1,n]\) 用线段树拆成 \(O(\log n)\) 段,把 \((k_x,b_x)\) 这个点放进每一段代表的节点;再把 \((k_y,b_y)\) 丢进 \(l_y\) 代表的节点到根的所有节点。

最后在每个节点上对两种点做闵可夫斯基和即可,因为不在上凸包上的 \((k_x+k_y,b_x+b_y)\) 都是用不到的!这里 \(p_x\) 不一定全部正确,但答案肯定是正确的,因为最后也只需保留 \((x,p_x)\) 的上凸壳。复杂度 \(O(n\log n)\)

30. ucup2-19H Minimum Cost Flow²

有人场上以为流量不能非负/xk

\(1\)\(n\) 任意路径的 \(\sum cf\) 都得相等,不然很明显能调整。 所以所有环的 \(\sum cf\) 都等于 \(0\) !随便求一组生成树,考虑每个非树边,把 \(u\)\(v\) 的路径和这条边拼起来即可得到一个环,最后有 \(m-(n-1)\) 个环,你发现这些环权值为 \(0\) 后就能保证所有环都满足条件了。

再和题目给出的 \(n-1\) 组限制拼起来就能得到答案了!

31. ucup2-6B The Doubling Game 2

思考怎么刻画这个合并的形式。把 \(u\) 的棋移到 \(v\) 上我们就连一条 \(u\)\(v\) 的边,注意到一条边是不会出现多次的,最后就形成了若干内向树。得到了这个森林后,要求对于每个点它的儿子权值分别是 \(2^0,2^1,\ldots,2^k\) ,最后自己权值是 \(2^{k+1}\)

考虑 dp ,设 \(f_{u,i}\) 表示 \(u\) 指向 \(fa_u\) ,且 \(u\) 权值为 \(2^i\)\(g_{u,i}\) 表示 \(fa_u\) 指向 \(u\)\(h_u\) 表示 \(u\)\(fa_u\) 没连边。

转移是容易的,就是一个状压的过程。分析一下复杂度,我们把儿子的 siz 从小往大排序再进行转移,可以发现到第 \(i\) 个儿子是状态数是 \(siz_{i}\) 级别的。如果抛开最后一个儿子,总状态就是 \(O(n\log n)\) 的了。而添加最后一个儿子只会使状态数翻 \(\log n\) 倍。更精细的分析是,因为最后算 \(f,g,h\) 用到的状态都是形如 \(2^k-1\) 的状态,所以这里有用的状态数只会翻 \(O(1)\) 倍。乘上转移的复杂度,复杂度 \(O(n\log^2n)\)

32. 1.22 T3

很 educational 的题!

第一步就是说,研究这种序列操作可以先从 01 序列的角度考虑。

那么设 \(b_i=[a_i\geq x]\) ,观察 \(b\) 需要多少次操作,设一共有 \(x\)\(0\) ,我们只需要看前 \(x\) 个数中有多少 \(1\) 即可,因为每次一定会把一个 \(1\) 换到后面,一个 \(0\) 换到前面。那拓展到排列,其实就是这样一个东西:对于 \((i.p_i)\) ,我们对 \(s_{i+1}\)\(s_{p_i}\)\(1\) ,最后要让所有 \(s_i\le m\)

这样就可以 dp 了,你把排列看成是下标-值的二分图,从左往右 dp ,设 \(f_{i,j}\) 表示考虑了 \(1\)\(i\) ,有 \(j\) 个值和下标还没匹配的方案数,要求 \(j\le m\) ,转移是容易的,复杂度 \(O(nm)\)

考虑优化,令 \(A_{i,i}=2i+1,A_{i,i-1}=i^2,A_{i,i+1}=1\) (这里下标从 0 开始),则我们要求的就是 \(f_n=(A^n)_{0,0}\) 。把 \(A\) 的特征多项式 \(|Ix-A|\) 求出来,即可得到 \(A^i\) 的递推式,那也就得到 \(f\) 的递推式了,直接线性递推即可。问题在于求 \(|Ix-A|\) 。考虑枚举 \(p_m\)\(m\)\(m-1\) ,可以得到 \(d_m=d_{m-1}(x-(2m+1))-m^2d_{m-2}\) 。可以写成一堆 2*2 矩阵乘起来的形式,分治计算即可。

不过有人直接推出 \(f_n=\sum\limits_{i=1}^{m+1}(-1)^{i-1}i!\tbinom{k+1}{i}^2f_{n-i}\) ,不是很懂怎么找的。

33. BZOJ2640 可见区域

怎么算这个可见区域呢,考虑我们把所有出现的线段端点和 \((0,0)\) 的连线按极角排序,把平面划分成 \(2n\) 段,然后对于每一段找到最低的线段即可。怎么加速呢,类似于 雨落葡萄园 这个题,由于线段两两不交,两个线段间的相对关系一定是固定的,直接用平衡树维护当前扫到的段上存在的线段,通过计算面积比较相对关系进行插入即可。这样就很容易算可见面积:把每一段中的最低线段围成的区域加起来即可。求删除一/二条线段后的最大面积也是容易的,只需要每次 split 出前三小的线段,预处理一下 \(a_x\) 表示删掉 \(x\) 的贡献和 \(b_{x,y}\) 表示同时删掉 \(x,y\) 的贡献即可简单运算。复杂度 \(O(n\log n)\)

34. USACO PT 口胡

T1:没啥技术含量的分类讨论。

T2: 我觉得出的挺好的一题。考虑倒着思考问题,一开始我们有一段 \([1,n]\) ,然后会从中间劈一刀,更大的一端我们称为最强段。另一端就已经废了,它内部断的顺序就不重要了,直接插进操作序列即可。记 \(dp_{i,j}\) 表示 \([i,j]\) 当最强段的概率,前缀和优化一下即可做到 \(O(n^2)\)

T3:考虑点边容斥,转化成计算 \(\sum (2^{S_1(x,y)}-1)(2^{S_2(x,y)}-1)\)。其中 \(S_1(x,y)\)\(\le x,\le y\) 的点个数,\(S_2(x,y)\)\(\geq x,\geq y\) 的点个数。拆一下式子,扫描 \(x\) ,变成区间乘全局和,线段树即可,复杂度 \(O(n\log n)\)

posted @ 2024-01-15 22:52  grass8woc  阅读(238)  评论(0编辑  收藏  举报