联赛题目研究

基础卷积练习题

看上去(max)的限制不好处理。
但是题目中(a,b)都特别小。
考虑枚举(a,b)的值为(x,y),新建两个数组(c,d),当(a_i=x,b_i=y)(c_i,d_i)赋值为(1)
(c,d)作or卷积,(>0)的部分对(f(x,y))(max)贡献到答案。
时间复杂度(O(2^nn^3))
或者把fwt的域扩展一下。就像在一些题目中,拓展行列式的域求多项式一样。使用一个长度为(m)的向量存储结果。
时间复杂度(O(2^nn^2))

小ω的树
由于题目没有修改边权,考虑kruskal重构树。
考虑每条边的贡献,由于点权非负,显然要选择尽可能多的点。
钦定一条边产生贡献,能选择的点是这条边对应子树的点。显然选择整颗子树更优。
现在,我们要支持修改。
也就是对树上的一条链的权值作加法。
链的情况是个经典问题。就是CF1178G的(nsqrt{n}log_2n)算法。
树的情况考虑轻-重链剖分。
把每条重链分块套用CF1178G的算法。
看上去时间复杂度会多log。
然而由于每条重链的长度(leq)链顶子树的大小。
假设子树的大小为(S)
由于轻儿子的子树大小(leq cfrac{S}{2}),所以修改的时间复杂度不会超过(sqrt{S}log_2n+sqrt{cfrac{S}{2}}log_2n+sqrt{cfrac{S}{4}}log_2n....=sqrt{S}log_2n)
所以这样子的时间复杂度还是(O((n+q)sqrt{n}log_2n))的,十分神奇。
实际上,可以套用Ynoi某题的可加负数做法做到(O((n+q)sqrt{n})),但是没有必要。

方格问题
https://www.cnblogs.com/ctmlpfs/p/13962254.html

僵尸
注意到每个僵尸占领的肯定是一个连通块。(Kruskal重构树上的一个子树)
并且在一个连通块内,能力值大的僵尸的连通块肯定包含能力值小的僵尸的连通块。
这给了我们一些启示。
(f_{x,i})表示(x)所在连通块中能力值最大僵尸为(x)
如果能力值最大的僵尸多于(1)个,则钦定编号最大的僵尸能力值最大。
考虑从子树(y)(f_{y,j})转移到当前点。
考虑:
1.(x)(y)在一个连通块内。
(i=j)
(f_{y,j}*)(僵尸(x)经过(i o j)的方案数)( o f_{x,i})
2.(x)(y)不在一个连通块内
2.1 (j>i)
则僵尸(y)必须不能进入(x)
实际上,如果上面的条件满足,则也蕴含了僵尸(x)不能进入到(y)这个限制。
(f_{y,j}*)(僵尸(y)不经过经过(i o j)的方案数)( o f_{x,i})
并且保证(y)中存在(j),不存在(i),这是因为(y o x)的边被断开。
2.2 (j<i) 同理可得
(f_{y,j}*)(僵尸(x)不经过经过(i o j)的方案数)( o f_{x,i})
初值是(f_{x,i})=[(x>=i)处最大的僵尸能力值]
注意前缀和优化。

f
由于其他求逆序对的做法不适合,考虑创造一个新的求逆序对的做法。
考虑按位分治的套路。设(solve(S,i))表示处理到(S)集合的第(i)位贡献的逆序对的个数。
考虑按顺序扫描(S)中的元素。然后问题转换成对(0/1)序列求逆序对。可以存储前面(0/1)个数解决。
(a_i)表示第(i)位贡献的顺序对的个数,(b_i)表示第(i)位贡献的逆序对个数。
注意到对一个位进行(xor),等于把一个位置的贡献从(a)变成(b)
所以题目要我们求出的就是若干个元素(c_i),每个可以取值为(a_i)或者(b_i),询问取值的和排序后的第(x)个元素。
由于位数较少,考虑折半。
考虑二分第(k)位的值(md),显然把左/右边的所有情况排序,维护一个指针就能求出(leq k)的情况的个数。
对于第二问,求出值(leq md-1)的数的个数,然后把(p)减去这个数。
然后我们要求的就是逆序对(=md)的值从小到大的第(p)位。
这同样可以折半。
把左边的值按照(x)从小到大排序,在右边求出值等于某个数的数的个数,可以倍增/二分求出。
这样子就成功求出了答案。

融入社会的计划
考虑简单dp,设(f_{x,i})表示考虑前(x)个位置,第(x)个位置改成(i)
(f_{i,j}+x-A_{i+1} o f_{i+1,x},l-jleq xleq r-j)
(f)打表/分析/猜结论可以得到(0leq f_{i,j+1}-f_{i,j}leq 1)
考虑归纳证明,在第一步,随着(j)的增大,一个点能够转移到的区间的左右端点都会向左移动。
能够转移到(x)(j)满足(l-xleq jleq r-x),就是(f_{i,l-x})
考虑(f_{i+1,x}-f_{i+1,x-1}=f_{i,l-x}-f_{i,l-x+1}+x-A_{i+1}-(x-1-A_{i+1})=f_{i,l-x}-f_{i,l-x+1}+1)
根据归纳假设(-1leq f_{i,l-x}-f_{i,l-x+1}leq 0)(0leq f_{i,l-x}-f_{i,l-x+1}+1leq 1)
得证。
发现答案就是(f_{i,j})合法的区间的左端点,发现把(f_{n,j})倒推回去也是个区间。
所以可以在线性时间内计算。

基础fake练习题
考虑题目的线性规划。
虽然题目有(0leq xleq 1)的限制,但是可以把它拆成(0 leq x)(xleq 1)的两个限制。
写出这个线性规划的对偶形式
得到如下问题:
1.删除一个路径,代价为(1)
2.删掉覆盖第(i)个点的所有路径,代价为(c_i)
考虑dp。设(f_{i,j})表示第(i)个点,子树中未被删除的路径的较浅点深度(leq j)的最小代价。
假设根节点的深度是(1),显然答案是(f_{1,0})
显然这个函数是常值分段函数,且随着(j)的增加而增加。
用线段树维护差分表。
显然当堆的大小(>c_i)时,删掉覆盖第(i)个点的路径更优。
所以我们每次删除较浅点较浅的路径即可。

God Knows

闷声刷大题

gdkoi2018 还念

城市建设
显然有线段树分治+LCT做法,但是并不是正解。
对询问进行分治。
注意到当前区间([l,r])的边都是未被确定的,所以我们考
虑使用询问外的边更新当前的答案。
考虑从当前区间转移到子区间。
把当前子区间内的所有边的边权设为(-inf)然后和当前询问外缩过的mst一起做mst。
则显然权值不是(-inf)且在当前mst的边一定会被选择。
可以把这些边缩成一个点。
把当前子区间内的所有边的边权设为(inf)然后和当前询问外缩过的mst一起做mst。
则显然权值不是(inf)且不在当前mst的边一定不会被选择。
可以删除这些边。
使用可撤销并查集维护。每做完一个区间就把它的修改全部撤销。
并不会证明时间复杂度。

God Knows
注意到我们删除的边的集合肯定都是不相交的,因为删除某边后和它相交的边都被去掉了。
考虑钦定一个顺序dp。设(f_i)表示删除前(i)条边的最小花费。
则枚举前面的一个点(j)(f_i=f_j+c_i),且(i...j)之间没有没被删除的边。
求出(i...j)之间是否没有没被删除的边可以使用前缀和。
但是这样子是(O(n^2))的。
考虑把((i,p_i))投射到平面上形成一个点(a_i),则判定两个点(a_i,a_j)之间有没有被删除的边,等同于判定两个点(a_i,a_j)之间形成的矩形内有没有点。
考虑哪些点可以转移到(i),显然是前面坐标(<p_i)的由(i)构成的单调递减栈的(f)的最小值。
考虑一个更加一般的问题。
我们要支持在某个点(p_i)内插入(i),询问(<p_i)形成的单调栈的(f)的最小值。
这是个经典的问题。时间复杂度为(O(nlog_2^2n))
由于题目的特殊性,可以得到更加优秀的算法。
每次新插入的数的值大于前面所有值。
这说明如果在线段树结构上把一个数插入到某个区间,则区间在这个数前面的数都不会出现在单调栈中。
在每个点维护一个栈表示当前区间的单调栈。
如果新插入的点在右侧,则这个栈肯定会被弹空。
如果在左侧,则单调栈在当前点左侧的元素全部被删除了,在当前点右侧的点还在。
维护前缀(max)即可轻松更新答案。
可以对于每个区间维护单调栈,这样子每个点只会被删除一次,时间复杂度降低至(O(nlog_2n))

黑箱

原文地址:https://www.cnblogs.com/ctmlpfs/p/13962469.html