联赛题目研究

基础卷积练习题

看上去\(\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的\(n\sqrt{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\to j\)的方案数)\(\to f_{x,i}\)
2.\(x\)\(y\)不在一个连通块内
2.1 \(j>i\)
则僵尸\(y\)必须不能进入\(x\)
实际上,如果上面的条件满足,则也蕴含了僵尸\(x\)不能进入到\(y\)这个限制。
\(f_{y,j}*\)(僵尸\(y\)不经过经过\(i\to j\)的方案数)\(\to f_{x,i}\)
并且保证\(y\)中存在\(j\),不存在\(i\),这是因为\(y\to x\)的边被断开。
2.2 \(j<i\) 同理可得
\(f_{y,j}*\)(僵尸\(x\)不经过经过\(i\to j\)的方案数)\(\to 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}\to f_{i+1,x},l-j\leq x\leq r-j\)
\(f\)打表/分析/猜结论可以得到\(0\leq f_{i,j+1}-f_{i,j}\leq 1\)
考虑归纳证明,在第一步,随着\(j\)的增大,一个点能够转移到的区间的左右端点都会向左移动。
能够转移到\(x\)\(j\)满足\(l-x\leq j\leq 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\)
根据归纳假设\(-1\leq f_{i,l-x}-f_{i,l-x+1}\leq 0\)\(0\leq f_{i,l-x}-f_{i,l-x+1}+1\leq 1\)
得证。
发现答案就是\(f_{i,j}\)合法的区间的左端点,发现把\(f_{n,j}\)倒推回去也是个区间。
所以可以在线性时间内计算。

基础fake练习题
考虑题目的线性规划。
虽然题目有\(0\leq x\leq 1\)的限制,但是可以把它拆成\(0 \leq x\)\(x\leq 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(n\log_2^2n)\)
由于题目的特殊性,可以得到更加优秀的算法。
每次新插入的数的值大于前面所有值。
这说明如果在线段树结构上把一个数插入到某个区间,则区间在这个数前面的数都不会出现在单调栈中。
在每个点维护一个栈表示当前区间的单调栈。
如果新插入的点在右侧,则这个栈肯定会被弹空。
如果在左侧,则单调栈在当前点左侧的元素全部被删除了,在当前点右侧的点还在。
维护前缀\(\max\)即可轻松更新答案。
可以对于每个区间维护单调栈,这样子每个点只会被删除一次,时间复杂度降低至\(O(n\log_2n)\)

黑箱

posted @ 2020-11-12 10:14  celerity1  阅读(122)  评论(0编辑  收藏  举报