5月做题记录
5月做题记录
✩ trick
✯ 会大部分,要\(tj\)提示
✬ 会小部分/完全没想到,看了\(tj\)才会
◈ 脑电波
✡ 有某一算法的神秘通用性质
⊗ 待补
[AGC005E] Sugigma: The Showdown
比较豪丸的题
考虑什么情况下可以无限的走,猜测是不是能在两个或三个点之间反复横跳
手模一下发现,如果红树上两点\((u,v)\),它们在蓝树上的\(dis>2\)的话,只要先手能走到这两个的其中一个,就能在上面反复横跳了
那么先从红树上剔除这些边,那么现在可以走到的边都是对应蓝树上\(dis\leq 2\)的
首先有个性质,先手所在的点在蓝树上一定始终在后手所在点的子树中,显然如果不在,那么只能跳到后手的父亲节点上,这样直接寄了
那么记\(r[x]\)表示先手起始点在红树上走到\(x\)的最短距离,\(b[x]\)同理,那么只保留所有\(r[x]<b[x]\)的点,找到先手所在连通块
如果里面有点\(y\),满足其某一条边在蓝树上对应距离\(>2\),则可以无限循环
否则答案就是这个快里最大的\(b[x]\)的两倍
复杂度\(O(NlogN)\)
[AGC005D] ~K Perm Counting
做法1
典题,显然可以二项式反演,现在求至少\(t\)个不合法的方案数
发现按\(\%k\)分成\(k\)个等价类,然后每个等价类分别算有至少\(t\)个不合法的,就可以\(f[i][0/1][t]\),这个\(0/1\)表示上一个选到的值是否会和当前可选的值冲突
复杂度\(O(NK)\)
做法2 ✩✬
from luogu 第一篇题解
这个有趣的就是在于它把答案转换到了网格图上
考虑如果把\((i,p[i])\)放到网格图中,以\(n=7\),\(k=2\)为例,画出网格图:
https://img.picui.cn/free/2025/05/12/6821b5d1d7eb8.png
那么我们就是要放\(n\)个车,要求车之前不能互相攻击到,且阴影位置不能放
然后还是考虑容斥选了\(t\)个阴影位置,考虑此时的方案,显然对于没有钦定的列就\(jc[n-t]\)的方案数了,对于钦定了的,其实就是相当于在这\(O(N)\)个阴影格子里选出\(t\)个,它们不会有两个在同行同列
进一步发现如果把同行或同列的阴影格子连边,那么每个联通块都是一个链,然后\(dp\)即可,其实这里就和上面差不多了
复杂度\(O(NK)\)
public round #8 t1
显然先求出一共需要补的魔的数量,然后显然能补就补,那么我们就会把\(a_i\)从小到大排序,每次代价就是\(a_i+(a_i-1)+(a_i-2)+...+(a_i-\min(m,a_i)+1)\),然后\(m-=\min(m,a_i)\)
现在我们的代价可以表示为一堆\(1\sim a_i\),和一个\(t\sim a_p\),这个\(a_p\)是最后操作到的那个
然后那个饼干,你手模一下就可以发现,相当于一个\(--a_i\)的操作,显然你会用到\(1\sim p\)上,且每次选最大的操作,这样答案就会减去这个\(a_q\)(\(a_q\)是当前最大的那个),当然这个\(a_p\)比较特殊,总之贪心处理的时候注意一下就行
复杂度\(O(NlogN)\)
public round #8 t2
\(a\)、\(b\),\(p\)、\(q\)混用,应该看得懂(
显然,这种可以连边\(x\rightarrow y\)表示\(x<y\),那么只要最后不成环就行
考虑拉出两条\(1\rightarrow2\rightarrow ...\rightarrow n\)的链,如果已确定\(q_i\),考虑\(check\)某个\(s_i\)是否合法,根据\(s_i\)的值连边\(p_i\)和\(q_i\)
那么成环当且仅当有两条链接两条链的边,设分别为\((1,a)-(2,b)\),\((1,c)-(2,d)\),满足\(a<c\),\(b>d\),即相交
此时成环当且仅当是\((1,a)\leftarrow(2,b)\),\((1,b)\rightarrow(2,d)\)
现在考虑合法的\(\{s_i\}\)的数量,设\(u_i\)表示\(a_x=i\)的\(b_x\),发现我们给边找方向时的操作大致类似于:
- 从\(i=1\)到\(n\)挨个考虑\(a_x=i\)的边\(a_x-b_x\)
- 若前面有边和该边相交和满足上面那个成环条件的一半,那么这条边定向确定了
- 否则该边定向任意
发现这个过程中,特殊的其实是那个,会另后面的边确定定向的边,进一步这些边显然两两不交且是朝上(连向\(a\)侧),提出这些边,我们的方案就是让这些边的朝向都向上,它们后面和它们相交的边也必须朝上,否则就朝下
显然是和所有\(\{s_i\}\)是一一对应的
那么\(f(p,q)\)就是\(q_i\)按对应的\(p_i\)排序后的上升子序列总数量
然后就很好\(dp\)了,\(dp\)的转移点就是所有已经确定了取值的\(q\),然后令\(q_0=0,q_{n+1}=n+1\),那么就是求必须以\(q_0\)开头,\(q_{n+1}\)结尾的上升子序列数量
\(dp[i][j]\)表示当前在\(q_i\),前面在上升子序列中的有\(j\)个是未确定的点
直接转移是\(O(N^4)\),用点值可以做到\(O(N^3)\)
practiceZ
显然没什么好的做法,考虑分块
对于查询的区间\([l,r]\),对于其中的散块可以直接查询,对应的\(a\)维护一个\(O(\sqrt N)-O(1)\)支持查询前缀的分块
然后考虑维护整块的答案
对于操作\(1\),首先可以转换成区间加,然后这样总的区间加次数就是\(O(N+M)\)的,可以势能分析一下,势能设置为\(\sum_i[a_i\neq a_{i+1}]\),势能永远\(\geq 0\),发现每次至多只会让势能\(+2\),显然总的就是\(O(N+M)\)级别的了
然后考虑现在操作变成对\([l,r]\)区间加,这个显然可以差分成对\([1,r]-[1,l-1]\)区间加\(v\),现在考虑对\([1,r]\)区间加\(v\)
对于当前整块\([L,R]\),答案的变化就是\(v\times\sum_{i\in [L,R]}\min(r,b_i)\),那么只需要对每个块都维护一个\(pre[t]\),表示\(b_i\leq t(i\in[L,R])\)的\(b_i\)的和以及\(i\)的数量
这个的维护就考虑操作\(2\)时的维护,整块的显然很好维护,散块的也很好维护,都可以做到\(O(\sqrt N)-O(1)\)
总复杂度\(O(N\sqrt N)\)
然后直接这样写空间也带\(\sqrt N\)不行,所以就对每个块单独处理,这里大概就会分成三步,然后存相邻两步间的一些操作的时候,注意合并相同的操作,不然就炸了,合并了就是\(O(N)\)的,不合并就是\(O(N\sqrt N)\)的
逆天做法
AT_wtf19_c1 Triangular Lamps Easy
首先操作有可逆性,那么就可以先全部放到同一行,这里让它们放到\(X=-\infty\)
考虑一个点能操作出的所有点都在同一行的局面,就是一个模\(2\)意义下杨辉三角的样子,证明就是走法大概就是一个\(C_n^m\mod2\)的样子,然后这个等价于\([n\&m==m]\)
考虑\(easy\)的情况,此时因为知道\(Y=0\),又因为现在所有灯都在\((-\infty,y)\)上,那么可以知道,\((-\infty,y)\)上有灯当且仅当\(\sum C_{x_i+\infty}^{y-y_i}\equiv 1\mod2\),\(C_{X+\infty}^{y-Y}\equiv 1\mod2\)
对于后者,想知道\(X\)的值,就可以逐位确定\(X+\infty\)在二进制下第\(i\)位是否为\(1\),而要\(check\)这个,就是\(check\)当\(y-Y=2^i\)的时候,\((-\infty,y)\)是否是亮灯的
那么就可以\(O(NlogN)\)的解决了
考虑推广到\(hard\)的情况,我们现在就不知道\(X\)、\(Y\)中任一一个的值了,所以考虑先确定下其中一个
发现\(Y\)是好确定的,即只需要找到\((-\infty,y)\)中最小的亮灯的\(y\),这个\(y\)就是\(Y\)
发现我们只需要任意找到一个亮灯的位置\((-\infty,y_0)\),然后就可以通过\(i=60\rightarrow 0\),\(check\)位置\((-\infty,y_0-2^i)\)是否亮灯,如果亮就减去\(2^i\),最后剩下的就是最小的\(y\)即\(Y\)了
这里核心就还是\(y-Y\subset X+\infty\)
现在考虑怎么找到一个亮灯的位置,发现我们只需要找到一个区间满足该区间内有奇数个亮灯的位置,就能递归下去
现在考虑怎么找到奇数个亮灯的区间
这里有个性质,对于\(n\),\([0,n]\)中,在二进制下属于\(n\)且模\(3\)同余\(v\)的数的数量的奇偶性记为\(f(n,[0,n],v)\)
发现对于任意的\(n\),\(f(n,[0,n],v)\),总有一个\(v\)的这个值为\(1\),这个可以用数学归纳法证明
那么我们现在找到一个\(v\),然后就在\([0,n]\)模\(3\)同余\(v\)的点中二分找到那个亮灯的点即可
复杂度\(O(Nlog^2N)\)
AT_wtf22_day1_d Welcome to Tokyo!
令\(x_i\)表示\(i\)点选了多少了,\(y_i\)表示区间\(i\)是否被选,那么有:
然后线性规划对偶得到
小登的文章写的很好的,推一手:https://www.cnblogs.com/fiosiate/p/18891406
显然会有:\(u_i=\max(0,1-v_i)\),\(w=\max_i \sum_{i\in[L_j,R_j]}v_j\)
然后可以给\(v_i\)一个组合意义表示区间\(i\)是否选上,那么现在就可以枚举\(w\),就是要选出尽量多的区间,且每个点被覆盖的次数不能超过\(w\)次
记\(w\)次的方案集合为\(f(w)\),\(f(1)\)是经典问题,每次找右端点最小的合法区间选择上就行
然后从\(f(i)\)到\(f(i+1)\)也是这样贪心即可
然后又有显然对于任意的\(k\),随着\(w\)的增大,\(\sum u_i\)不升,但\(kw\)部分至少加\(k\),这就意味着这是一个凸函数的样子,那么查询的时候二分一下就好,双指针
复杂度\(O(NlogN)\)
ARC135F Delete 1, 4, 7, ...
考虑记\(f^k(x)\)表示操作\(k\)次后,第\(x\)位上的值,那么会有\(f^k(x)=f^{k-1}(f(x))\)
考虑\(k\)比较大的时候,这时候直接求复杂度是\(O((\frac23)^KNK)\)的
然后考虑如果\(k\)比较小,这里有个性质:
\(f^k(x+2^k)=f^k(x)+3^k\),可以归纳证明
- \(k=1\)
由定义可得
- \(k>1\)
然后直接求是\(O(k2^k)\)的,还是不行,考虑能不能把复杂度降到\(O(k2^{\frac k2})\)的级别
那么考虑把\(k\)拆成\(x+y\),要求的就是
考虑设\(g(b,x)\)表示后面那个\(\sum\)里的值,显然有转移:
\(g(b,x)=g(b,x-1)+g(b+2^{x-1}\times3^y,x-1)\)
发现\(b\)的值域太大了,但是注意到\(g(b,x)\)可以规约到\(g(b\mod 2^y,x)\)来求
这样复杂度就是\(O((k+logN)2^{\frac k2})\)的了
平衡一下复杂度即可
P9293 [ROI 2018] Addition without carry
把\(a_i\)按降序排序
首先考虑得到答案可能的位数\(p\),显然有:\(p=\max\{l_i+i-1\}\)或\(p=\max\{l_i+i\}\)
考虑用函数\(f(a,p)\)表示对于数组\(a\),答案最高位\(\leq p\)是否合法,以及对应的答案,记\(h_a=\max\{l_i+i-1\}\)
显然如果\(p<h_a\),直接不合法
否则来\(check\)这个\(p\)是否合法:
- 若\(p\geq h_a\)
找到最小的\(x\)满足\(l_x+x-1=h_a\),显然现在把\(a_{1\sim x-1}\)删除,删除\(a_x\)的最高位,然后递归\(f(a',h_a-x)\),如果返回不合法进下一步
- 若\(p\geq h_a+1\)
此时显然是可以合法的,把\(a_{1\sim x}\)都删除,递归\(f(a',h_a-x+1)\)
记\(L=\sum l_i\),显然\(h_a\)是可以线段树/平衡树维护的
考虑复杂度怎么样,显然主要是考虑碰到不合法的情况的时候
注意到如果一个\(f(a,p)\)不合法,那么\(f(a,p)\)只会往下递归一次,那么复杂度\(T(a,p)=T(a,p-?)+O(?logL)\),那么就是\(O(l_ilogL)\)
再考虑对于一个合法点,它当前第一次递归失败后,第二次递归下去后,因为\(a_{1\sim x}\)被删除,即\(l_{1\sim x}\)不再有贡献,那么总的复杂度就是\(\sum O(l_ilogL)=O(LlogL)\)
二进制分组
CF710F String Set Queries
首先这个删操作可以独立出来,答案就是加操作的答案-删操作的答案
然后考虑二进制分组+\(trie\)维护
复杂度\(O(\sum|s_i|logN)\)
要注意回收标号,不然会\(MLE\)
[UOJ46] 【清华集训2014】玄学
因为\(M\)不一定是质数,所以必须得采用合并得到答案的形式
对操作二进制分组,然后这里的维护很智慧啊,我一开始想的唐氏维护就是重构的时候,前缀后缀主席树维护,这里就考虑线段树上直接维护所有操作,只要给线段树开成一个\(2\)的倍数,那么此时所有子树内满叶子的点可以\(up\),然后具体每个点内记录所有子树内的操作对应到每个区间的操作,大致记录为\(([l,r],k,b)\)这样
复杂度$O(QlogNlogQ)
P5304 [GXOI/GZOI2019] 旅行者
这种感觉就属于想得到就很简单,想不到那就完蛋(废话)
注意到因为我们要求的两两间最短的,所以考虑这样一个策略,每次把所有\(k\)个城市分成两个集合\(A\)、\(B\),算\(A\)中的点到\(B\)中的点的最短距离,这个只需要新建点\(S\)、\(T\),然后\(S\)连向\(A\)中所有点,边权是\(0\),\(B\)中所有点连向\(T\),边权是\(0\),\(S\)、\(T\)间的距离就是要求的
然后考虑用尽量少的\((A,B)\),使得所有点对\((i,j)\)都存在一对\((A,B)\)满足\(i\)、\(j\)不在同一个集合中
可以想到根据标号的二进制,操作\(logN\)次,枚举位数\(i\),每次把该位是\(0\)的分到一组,是\(1\)的分到另一组
复杂度\(O(MlogNlogM)\)
P4585 [FJOI2015] 火星商店问题
可以直接线段树下标为时刻,然后每个节点维护子树内所有修改的\(trie\)树,对于商店编号\([l,r]\)的限制,直接一个持久化\(trie\)就行
用编号作下标,\(trie\)树维护时刻更好,因为时刻的限制是一个后缀
这样时空是\(O(Nlog^2N)\)的
然后也可以分治,就整体二分一下答案,考虑当前要check的其实就是当前值的区间里的所有数,是否在时间\([l,r]\)、位置\([a,b]\)内有值,就是二维数点
时间\(O(Nlog^2N)\),空间是线性的
这道题,线段树分治啥的,本质上也算是二进制分组,不过是像 [UOJ46] 【清华集训2014】玄学 的做法一样,用线段树来维护这个二进制分组
[BZOJ2989]数列
给定一个长度为n的正整数数列a[i]。
定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]|。
2种操作(k都是正整数):
1.Modify x k:将第x个数的值修改为k。
2.Query x k:询问有几个i满足graze(x,i)<=k。因为可持久化数据结构的流行,询问仅要考虑当前数列,还要考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为同样的数值,按多次统计)
首先显然可以离线下来\(CDQ\)分治
在线的话就可以考虑二进制分组,然后每个组内按\(x\)从小到大拍,然后求的时候大概就会是求前缀的满足某个限制的\(a[x]\)的数量,以及剩余后缀的满足某个限制的\(a[x]\)的数量
复杂度\(O(Nlog^2N)\)
然后还有就是可以曼哈顿距离转切比雪夫距离,不过其实和上面那个本质一样
现在就是一个矩阵内二维数点,发现转换成和上面一样的
网络流
[TopCoder] CurvyonRails
相当于是要求每个点要和周围的点连俩边
网格图就是二分图,先染色,建边\((S,白,2,0)\),\((黑,T,2,0)\),然后相邻的点再连边\((1,0)\)
考虑这个分数怎么搞,那么就是要求该点相连的两点不在同一直线上,那么可以把原本那个相邻点的\((1,0)\)的边改一下,以白点为例,让它对应的黑点分成两组,分别是行相同和列相同的组,然后新建行点列点,白点向行点列点连边\((1,1)\)和\((1,-1)\)即可
点、边、流量都是\(O(NM)\)的,复杂度是\(O(N^2M^2logNM)\)
[agc034D] Manhattan Max Matching (+Hard Ver. 模拟网络流)
这个绝对值能拆成四种,显然直接拆开然后取最大值就是对的了
直接\((S,红,1,0)\),\((蓝,T,1,0)\),然后中间放四个点分别表示四种类型,红和蓝再连上去就行
流是\(N\),点是\(N\),边是\(N\),复杂度\(O(N^2logN)\)
然后直接写\(SPFA\)的也可以过,因为我们每个流每次至多经过\(O(12)\)个点
这里就涉及模拟网络流了
因为我们的边的容量是\(1\)的,也就是说,每条边流过就反向一次,我们称\(S\)、\(T\)、以及中间四个点是特殊点,那么实际上我们可以简化成这六个点的互相抵达关系
那么我们每次拿出最长路,再\(O(logN)\)的更新即可
复杂度\(O(NlogN)\)
no source
给定\([1,n]\)上若干区间,求至少选多少个能使每个位置至少覆盖\(k\)次
\(n\leq 1e5\),\(k\leq10\),\(5s\)
可以先考虑恰好\(k\)次的情况,发现此时,可以把所有区间分成\(k\)组,每组都恰好把\([1,n]\)全给覆盖了一遍,那么直接建边\((l,r+1,INF,1)\),让最后的流为\(k\)即可
那么对于至少,发现我们可以通过把一些区间缩小,使得其变成恰好的情况,那么考虑这样建图:
拉三条线,第一条和第三条有\(i\rightarrow i-1\),第二条是\(i\rightarrow i+1\),然后对于区间\([l,r]\),建边\((第一条的l,第三条的r+1,INF,1)\),然后对于每个\(i\),再连边\((第二条的i,第一条的i,INF,0)\),\((第三条的i,第二条的i,INF,0)\)即可
[arc122F] Domination
和上道题类似
复杂度\(O(NKlogN)\)
[LOJ6007] 方格取数
经典题,先黑白染色,然后黑的和\(S\)连通是选,白的和\(S\)连通是不选,相邻的边再连\(INF\)边,求总的数量减去最大流即可
[CF786E] ALT
显然路径向点连边,然后最小割,可以线段树优化下建图
[TopCoder] RabbitWorking
很牛啊
显然能想到二分,现在就是\(check\)能不能有\(mid\times(200k-k^2)-s\leq 0\)
因为相当于是要求点的导出子图,考虑建闭合子图模型,这里考虑点连向所有它的边,也即选了点必选它的边,这样显然不行,因为边的权值贡献就算不对,但是可以这样赋值:每个点的值为所有相连的边的权值和,边的值为它的权值的负数,这样就没有问题了
似乎是典的trick,可能我网络流做少了第一次见(
这个\(k\)肯定要拆了,显然\(mid\times 200\times k\)能拆到每个点头上作为点权,后面的\(mid\times k^2\)不好拆,考虑点的导出子图里什么是\(N^2\)的,显然就是所有点的对数,那么所有点之间连一条权值为\(2mid\)的边,然后再给每个点补个\(mid\)的权
然后会想能不能边连向点啊,因为显然这个比较第一眼就想干的
这里显然就边的权就是它的权值,然后还是要拆\(mid\times(200k-k^2)\),然后前者还是每个点的权值算上一个\(200mid\),后者同样也算作边,然后也是边连点即可
[P4313] 文理分科
经典题,还是最小割,这个和网格图没啥关系了,就连\(S\)表白,连\(T\)表黑,然后对于那些四联通的几个点必须全黑/白的,新建一个点,然后向这些点连\(INF\)边,再根据需要的颜色,连到\(S\)/\(T\)上
[qoj1197] Draw in Straight Lines
也很牛啊,首先显然你同行同列的操作不会有交集的,然后只要知道总共的操作,你就知道操作的顺序了,具体的:黑的行列操作\(\rightarrow\)白的行列操作\(\rightarrow\)单点操作
然后考虑弄出新的变量\(b_{r/c}[i][j]/w_{r/c}[i][j]\),表示\((i,j)\)是否被黑/白的行/列操作染色过,然后分类\((i,j)\)的目标颜色,再根据这几个变量的具体值可以得出它是否还需要单点操作
然后可以把这四个变量提出来最小割,代价是简单的
[LOJ2384] 切糕
同上,复杂度\(O(NMK)\)
[arc129E] Yet Another Minimization
这个就可以转换成如果\(x_i\leq v\&\& x_j>v\)就有\(w_{i,j}\)的代价的样子,然后再压缩一下这个图就行
点数\(O(NM)\),边数\(O(N^2M)\),复杂度\(O(N^4M^3)\)
[arc125E] Snack
先建图,然后最大流转最小割,然后发现可以贪心,最后复杂度\(O(NlogN+M)\)
no source
长度为\(n\)的序列,每次可以选俩数\(x_i,x_j(i<j)\),然后删掉它们并获得\(x_i-x_j\)的分数,对每个\(k\)求至多操作\(k\)次的最大分数
\(n\leq 5e5\)
模拟网络流
建图是简单的,大概就三层嘛
你手模一下发现可以变成,每次取出最大的\(x_i-x_j\),要么\(i<j\),要么\(i>j\)且第二层\(i\)、\(j\)间的边的一个值\(h>0\),然后前者会令\(i\)、\(j\)间的\(h+1\),后者会令\(h-1\)
这个线段树维护即可
复杂度\(O(NlogN)\)
如果把第二层中间的流量换成\(1\)也差不多的做
[hdu6978] New Equipments II
同样模拟网络流
建出图,然后每次就是找最大的\(a_i+b_j\),满足可以走出\(s\rightarrow i\rightarrow ...\rightarrow j'\rightarrow T\)的路径
注意到我们现在边的形式大致就是,中间是个完全图,大部分箭头是朝右的,\(O(N)\)个朝左,\(O(K)\)对点间没有边
然后就按\(a_i\)大到小枚举\(S\)能走到的\(i\),然后给当前\(i\)能走到且没被标记过的右侧点打标记\(a_i\),然后如果它们有朝左的边,就走过去给那个左侧点打个特殊标记即可
复杂度\(O(N(N+K))\)

怎么五月了wc
浙公网安备 33010602011771号