省选之后的一些专题
省选之后的一些专题
oyds - 杂题
希望不会重名(因为之前好像有一个oyds的专题)
P9523
一个有点意思的串串题 + 区间 dp。
题面
给定串 \(S\) ,每次可以进行如下操作:
- 用 \(A\) 代价写下一个字符
- 用 \(B\) 代价剪切当前写下的字符串,即
Ctrl+A,Ctrl+X
- 用 \(C\) 代价粘贴当前剪切板上面的字符串到目前串的末尾,即
Ctrl+V
求打出来 \(S\) 的最小代价,\(|S|\le 2500\)。
Sol
考虑过程是怎么样的,由于每次是剪切,那么一定是最后手中握着一个串 \(T\),然后开始打 \(S\),每一次遇到一个位置可以放 \(T\) 就放上 \(T\),否则就是打单个字符。
这样就可以快速想到一个比较显然的区间 dp:
相当于枚举 \(T\) 和其出现的次数 \(t\)。
但是这个复杂度是不太能接受的,但是看起来确实是有前途的,不难发现有些时候两个区间找到的 \(T\) 是相同,这样是比较浪费之间的。不妨反过来做,考虑确定 \(T\) 的时候,怎么去给别的转移,直接写还是 \(\mathcal{O}(n^4)\),但是真的要去枚举 \([l,r]\) 吗?并不需要,其实只需要枚举所有顶着边缘的即可,即枚举 \([l',r']=T\) 然后往前跳,跳到第一个 \([l'',r'']=T,r''<l'\) 的位置,更新 \(f_{l'',r'}\) 即可,之后加上 \(f_{l,r}=\min\{ f_{l,r},f_{l+1,r}+A,f_{l,r-1}+A\}\) 的情况正确性就能保证了。复杂度也就优化到调和级数 \(\mathcal{O}(n\log n)\)。前面的跳的过程可以简单预处理。
qoj1249
题面
有若干个鱼在池塘里面,每一次进行如下操作:
- 加入一条大小为 \(x\) 的鱼
- 删除一条鱼
- 询问:假如加入一条大小为 \(k\) 的鱼,之后这条鱼可以不断地吃比起小的鱼,如果这条鱼吃了一条大小为 \(x\) 的鱼,其大小会变大 \(x\)。问最少吃几条鱼能够让这条鱼大小至少为 \(y\)。
\(n,q,V\le 3\times 10^5\)。
Sol
先想一下吃的过程,就是大鱼每一次吃比起小的尽可能大的鱼。
有些时候,一个鱼吃了另一条鱼,可以让其吃掉一条之前吃不到的鱼。注意到这个过程最多进行 \(\mathcal{O}(\log V)\) 次,称这个过程为“升级”。
思路逐渐出来了,每一次考察一条鱼吃哪些鱼能够“升级”即可,复杂度 \(\mathcal{O}(q\log V\log n)\)。
具体实现上,维护一个平衡树,支持回滚即可。但是写起来花了非常久时间,主要是回滚有点鬼畜,而且有傻子没有必要的多加了一只 \(\log\)。
或者写权值线段树,这个感觉上还好一点。
qoj3994
请自行阅读题面
Sol
关键点在于考虑最优策略是什么(这类题都是这样的)。
如果 \(T_2\le T_1\) 那么蓝没有任何意义,也就是说这时候一定是直接回血,而且显然在血量等于 \(2\) 的时候才回血。这一部分写一个简单的 dp 即可。
如果蓝有意义,发现如果一个关卡不能回蓝,那么还是只有血量在 \(2\) 的时候才回血。但是如果一个关卡能够回蓝,那么这时候用蓝回血不一定没必要,因为蓝无限。
也就是说需要找到一个 \(lim\) 满足蓝小于 \(lim\) 的时候回血,否则不回血。这时候设计 \(f_{i,j,k}\) 表示在关卡 \(i\) 的时候血量和蓝量为 \(j,k\) 即可。
感觉这个看代码理解更快
for(int i=n;i>=1;i--){
if(hav[i]){
for(int h=2;h<=H;h++)for(int s=0;s<=S;s++)g[h][s]=inf;
for(int L=2;L<=H;L++){
f[i][L][S]=(f[i+1][L][S]*p[i]+(1-p[i])*t1+1)/p[i];
for(int h=L+1;h<=H;h++)f[i][h][S]=1+f[i+1][h][S]*p[i]+(1-p[i])*f[i][h-1][S];
for(int h=2;h<L;h++)f[i][h][S]=(L-h)*t1+f[i][L][S];
for(int h=2;h<=H;h++)for(int s=0;s<S;s++)f[i][h][s]=f[i][h][S];
for(int h=2;h<=H;h++)for(int s=0;s<=S;s++)g[h][s]=min(g[h][s],f[i][h][s]);
}
for(int h=2;h<=H;h++)for(int s=0;s<=S;s++)f[i][h][s]=g[h][s];
} else {
for(int h=2;h<=H;h++){
for(int s=0;s<=S;s++){
if(h==2&&s==0)f[i][h][s]=(f[i+1][h][s]*p[i]+(1-p[i])*t2+1)/p[i];
else if(h==2)f[i][h][s]=f[i+1][h][s]*p[i]+(1-p[i])*(f[i][h][s-1]+t1)+1;
else f[i][h][s]=1+p[i]*f[i+1][h][s]+(1-p[i])*f[i][h-1][s];
}
}
}
}
AtCoder-utpc2021_l
题面
一个四联通的网格,初始有一些位置被堵住了。Alice 和 Bob 玩游戏,每一次可以堵住一个格子,如果堵完止呕 \((1,1)\to (n,m)\) 不连通,那么堵住的人就获胜了,求谁必胜。复杂度限制 \(\mathcal{O}(nm)\)。
Sol
先不上结论,先考虑一下最终局面会是怎么样的。
如果开始的时候 Alice 能够一步获胜就会获胜。反之,两者都会避免出现让对方一部获胜的情况,如此下去,最后一定剩下两条不交的从 \((1,1)\to (n,m)\) 的路径,然后就能够决出胜负。
注意到这两条路径的长度奇偶性相同,也就是说,只需要开始判断 Alice 能否一步获胜,如果不能判断没有被初始堵住的位置的奇偶性即可。
hz - 杂题
上周在造数据,没什么时间写总结,本身也没有写几道题。
上课写专题,晚自习或者别的时候写一下 CM 的。
Grouping
题面
物品分组,多少组都可以,如果 \(i,j\) 在一组会产生 \(a_{i,j}\) 价值。
\(i,j\le 16\)。
Sol
?随便做
CF1741G
原来前面两题是状压练习。
题意
给一个无向连通图,有 \(f\) 个朋友在节点1,每个人的家在 \(h_i\) ,其中有 \(k(k \leq 6)\) 个朋友没有车,有车的朋友可以开车载任意数量的顺路的朋友回家。问最后无法被开车送回的朋友的最小数量。
顺路:他的家在有车朋友回家的最短路上的朋友
Sol
注意到大部分人都有车,只需要考虑那可怜的 \(k\) 个人即可。状压,令 \(f_{i,S}\) 表示在 \(i\) 点处,\(S\) 集合的人能否都顺路到这里,这里先不考虑谁开车,只是通过一个简单的 bfs 转移即可。
然后合并每一个有车人家的位置的状态即可。
P3226
仍然是状压,但是有点乱搞。
题面
从 \(\{1,2,\dots n\}\) 集合里面选出一个子集,满足如果 \(x\in S\) 则 \(2x\not\in S,3x\not\in S\)。
\(n\le 10^5\)。
Sol
需要一点构造技巧,选择一个数 \(x\) 会限制两个数,那么不妨把这个数表画出来。第一行即 \(1,2,4,8\dots\) 第二行是 \(3,6,12,24\dots\)。对于这样的数表,要求每次选择不能选择相邻两个数,注意到长宽都是 \(\log\) 级别的,直接状压即可。
当然,由于有些数不会存在第一个数表里面,如 \(5\),把其他的表构建出来,最后 \(\prod\) 起来就是答案。
至于复杂度分析,初步看起来是不行的。但是会发现直接写是能通过的,甚至不需要任何优化,大概原因是后面几行的数字只会越来越少,到不了极限。
P2345
题面
给定一个网格图的第一行和最后一行的颜色,颜色数量 \(\le 4\),问有多少种方法填满网格满足相邻两个颜色不同,行数 \(\le 1000\),列数 \(\le 8\)。
Sol
同样是暴力状压 + 减枝。有两个大方向,一种是记录每一行的状态,然后把可行转移跑出来,但是我这样写不是很优秀。另一个就是类似轮廓线的思路,记录折线上方的情况。这个加上几个剪枝,如不转移为 \(0\) 的值就可以通过。
CF449D
题面
给出一个长度为 \(n\) 的序列 \(a_1,a_2, \cdots, a_n\)。求构造出一个序列 \(i_1 < i_2 < ... < i_k(1\le{k}\le{n})\) 使得 \(a_{i_1}\&a_{i_2}\&\cdots \&a_{i_k}=0\)(其中 \(\&\) 表示按位与)的方案数模 \(10^9+7\) 。
Sol
用到 SOS dp 的技巧,也就是高位前缀和。记得之前在 nfls 有一个位置也写过这个东西的,但是那个处理的不是二进制。
基本的思路就是,对于 \(k\) 维前缀和,每一个维度单独做一次就得到了最终前缀和的答案。
对于本题,设 \(f_S\) 为和为 \(S\) 的方案数,令 \(g_S=\sum_{S\subseteq T}f_T\),注意到 \(g\) 是比较好求的,只需要有多少个数其是包含 \(S\) 的,之后相当于这些数里面任选都可以满足答案。最后对于 \(g\) 高维差分就得到了答案。
历史研究
题面
给定数列,若干询问求 \([l,r]\) 中最大的“数字 $\times $ 这个数字的出现次数”。\(n\le 10^5\)。
Sol
经典的回滚莫队。
普通莫队做这个问题遇到的唯一问题就是缩小区间的时候无法快速更新答案,这时候考虑回滚莫队。正常莫队操作之后,假设目前考虑所有左端点在 \(B\) 块里面的询问区间,对于所有的 \(r\in B\) 直接暴力计算答案。剩下的注意到右端点是有序的,但是左端点是无序的,暴力扩展右端点,每次扩展的时候,记录一下 \([B_r,r]\) 的答案。这样就可以做到左端点回滚了。
什么意思?注意到左端点全部在 \([B_l,B_r]\) 区间里面,也就是说 \(>B_r\) 的位置无论如何都会被统计到答案里面。这样就可以做到回滚的效果了,这样满足回滚的过程和(左)端点的扩展过程都是 \(\sqrt{n}\) 级别的,而且避免了做缩小区间更新答案的过程。这也是回滚莫队的核心,即避免某一个操作(扩展或者收缩)。
复杂度根号。
P4396
题面
给定序列,若干询问,求 \([L,R]\) 当中数字在 \([A,B]\) 中有多少个数字,且这些数字的不可重集大小。
\(n,m\le 10^5\)。
Sol
没错,可以值域分块,但是我选择 cdq。
考虑一个位置表示成 \((x,a_x,p_x)\),相当于一个点要满足 \(x\in[L,R],a_x\in [A,B],p_x\in[1,L)\)。相当于一个三位数点问题,cdq 即可。
P5309
理解能力变弱了。
题面
给定序列,每一次修改形如给所有 \(y,y+x,y+2x\dots\) 的位置 \(+v\),区间查询。
\(n,q\le 2\times 10^5\)。
Sol
分成两部分,如果 \(x>\sqrt{n}\) 直接暴力修改,因为修改数量小于 \(\sqrt{n}\)。
如果 \(x<\sqrt{n}\) 考虑 \(x\) 相当于把整个序列分成了若干长度为 \(x\) 的块。对于这种块(注意这里和第一个部分的块完全是两个不同的概念),修改的位置相对于每一个块是一样的。也就是其实只需要在一个长度为 \(x\) 的块上面单点修改即可。
对于第一个部分的查询就是普通分块,第二个部分的查询相当于要知道 \([l,r]\) 之间包含了多少个整长度为 \(x\) 的块,这些块都能全部贡献,剩下还剩下两边零散的部分,注意到这里直接暴力跳是错误的,因为要遍历所有的 \(x\) 复杂度会劣化到 \(\mathcal{O}(qn)\) 因此记录一下前后缀和就可以做到对于一个 \(x\) 能 \(\mathcal{O}(1)\) 查询。
P4168
题面
给定序列,求区间 \([l,r]\) 的绝对众数(有多个区最小),强制在线。
Sol
给上面的一个题有点像,但是强制在线导致不能直接用莫队,这种不可叠加的东西没有直接的 ds 能够维护,考虑分块。
想一下分块询问是什么样的,即中间的整块和两边的散块合并。回到这个题,计算中间的整块的众数,不妨设 \(p_{i,j}\) 表示 \([i,j]\) 块中的众数是什么。同时注意到,如果众数不是整块中的众数,那么就只能是在散块中的众数了。那么不妨假设 \(c_{i,j}\) 表示 \(i\) 在前 \(j\) 块出现过几次,相当于前缀和,这样就可以解决散块的数字了。
P4462
题面
给定序列,每次询问 \([l,r]\) 区间内有多少个连续子区间满足异或和 \(=c\)。\(c\) 初始给定。
Sol
感觉放这个题的目的是为了讲在线做法——大力分块。
离线注意到 \(c\) 是固定的,一切就变得简单了。记录前缀和莫队即可。
cdw - 杂题
CF1083F
题面
给定两个序列 \(a,b\),等长度,定义一次操作为,对于 \(a\) 序列一段长度为 \(k\) 的连续字段全部异或上任意一个数 \(x\)。定义这两个序列的相似度为将 \(a\) 变为 \(b\) 的最小操作次数。可能无解
单点修改并每次查询相似度。
\(n,q,k\le 10^5,a_i,b_i\le 2^{14}\)。
Sol
区间操作,第一反应除了 ds 以外就应该是差分。先对两个序列差分,差分之后再将两个序列合并。这下变成:
- 操作:将 \(a_i,a_{i+k}\) 同时异或上 \(x\)
- 询问:将 \(a\) 全部变成 \(0\) 的最小操作次数。
注意到第一个操作可以将 \(a\) 按照 \(\bmod k\) 分成若干条链,每一条链是独立的。然后思考怎么样求最小的答案,显然贪心是最合理的,因为后面一定不影响前面的东西,如果 \(a_i\neq 0\) 那么就让其异或上自己。
下面问题是如何快速计算最优解,会发现,一个数按照我们的贪心策略需要被操作当且仅当这个数的前缀和(链上的)\(\neq 0\)。证明显然,现在问题变成了对于“差分之后的前缀和”进行后缀修改,然后求有多少个 \(0\),这个通过分块是好解决的,因为值域比较小,暴力记录每一个块里面有的数即可。复杂度 \(q\sqrt{n}\)。有解当且仅当,显然是每一条链的最后一个元素都 \(=0\)。
再实现上面,如果真的去模拟出来每一个链表之后分块是很愚蠢的,因为要开各种东西。有一种好的方法是把所有链表接起来,形成一个序列,对这个序列分块。这样修改从后缀变成了区间,但是反正是分块所以复杂度没变。
P8544
太久没做题了,看到这个题真的让人眼前一亮。
题面
给定长度为 \(n\) 的序列 \(a\) 和长度为 \(m\) 的序列 \(b\)。对于一个 \((n+1)\times t,t\le m\) 的矩阵 \(B\) 定义
对于 \(B\) 有若干限制:
- 同一行中的数字各不相同
- 同一列中,相邻的两个数字不能相同
- 所有元素 \(\le m\)。
给定 \(n,m,a,b\),求 \(\min f(B)\bmod 10^9+7\),\(b,m\le 10^5\)。
Sol
看到之后手玩了一下,第一反应,这个矩阵是不是有点诈骗?因为对于列的限制只在于相邻两个数的,因此,如果找到了前两行的最优解,之后每一次奇偶交替填就能够保证两行之间的答案一直是这个最优答案。
那么问题就和 \(a\) 无关了,现在考虑怎么样求两行的答案。然后发现这个好像没有很好的方法求……
匹配!因为每一个点作为起点只能被用一次,作为重点只能用一次。那么不妨进行建模,对于 \(b\) 序列,每个点分为入点和出点,从源点向所有的入点连容量为 \(1\) 的边,出点同样连向汇点。中间部分连边加上费用即可,费用定义为 \(\sum_{\min(u,v)}^{\max(u,v)}b\) 即可。
但是真的要跑费用流就有点过于 naive 了,复杂度显然会爆炸。这种情况不妨抛开费用流,考虑模拟费用流。不过这个题还不能完全抛开,现在这里埋一个伏笔。
我们需要观察一系列的性质,因为杂乱匹配一看就是没有前途的。考虑 \(t=m\) 的时候,抛开费用流的模型,直接在 \(b\) 序列上面考虑,不妨在 \(b\) 上面连接所有 \(l_i\to r_i\) 的边,每个点的出度和入度都恰好为 \(1\),这种连边方式是很经典的,会形成若干个独立的环。这时候做一个重要的观察,就是在这个图里面,边一定不会相交,形式化的,如果 \(A<B<C<D\) 那么 \(A\to C,B\to D\) 一定劣于 \(A\to B,C\to D\)。这样告诉我们一个事情,在同一个环内,一定是 \(u_1\to u_2\to u_3\to \dots \to u_k\to u_1,u_1<u_2<u_3\dots\) 的结构。在考虑环与环之间的关系,两个环如果有相交肯定也不好,原因和上面的一样,合并成一个环即可。两个环包含看起来更不合理了。这些证明都是非常平凡的。
总结来说,最后相当于把序列分成若干连续段,每一段都是一个环。还可以再进一步,因为一个大小 \(\ge 4\) 的环可以拆成很多个大小为 \(2,3\) 的环答案一定不会劣。这是极为优美的。
然后考虑 \(t<m\) 的时候,此时可以有:一个点空着不选或者出现一条链。但是这两个的存在并不会打破上面的规则,对于链,不妨拆掉 \(u_k\to u_1\) 的边,这样形成的结构还是类似的。此时就可以 dp 了,令 \(f_{i,j,0/1}\) 表示考虑到 \(i\) 点,已经有了 \(j\) 条边,且这个点是否还要往下连(链)。有如下转移
- 延续上一次的链 \(f_{i-1,j-1,1}+b_{i-1}+b_{i}\to f_{i,j,1}\)
- 新开一个链 \(f_{i-2,j-1,0}+b_{i-1}+b_{i}\to f_{i,j,1}\)
- 注意链随时可以断掉,因此转移上面两个之后 \(f_{i,j,1}\to f_{i,j,0}\)
- 加一个长度为 \(2\) 或 \(3\) 的环。
- 跳过这个点
但是这样复杂度还是不行的,此时就要收回之前的伏笔了。因为这是一个费用流的模型,费用流模型有经典结论,流量关于答案的图像是一个下凸壳的右半部分,这个结论好像之前某次凸性专题里面就提到过。由于是凸的,而且是形如选择 \(t\) 个区间的形式,而且如果没有选的个数的限制答案是很好求的,因此可以直接 wqs 二分优化到 \(\mathcal{O}(m\log V)\) 的复杂度了,别忘要乘 \(\sum a\) 得到最后的答案。
ARC152E
题面
数轴上有 \(2^n-1\) 个点依次排开,可以理解为坐标从 \(1\to 2^n-1\) 的整数。每一个点有一个权值,权值恰好是一个 \([1,2^n-1]\) 的排列,还有一个数值 \(Z\)。现在这些点要动起来,定义 \(L_i\) 表示这个点左边所有点值的异或和再异或上 \(Z\),\(R_i\) 定义同理,现在一个点会往 \(L,R\) 大的一边运动,速度为单位速度,如果 \(L=R\) 那么这个点就不会动。当两个点撞到了一起之后会合并成一个点,这个点的权值为两个点权值的异或和,然后重新判定运动方向。
问在 \([0,2^n-1]\) 的范围内,有哪些 \(Z\) 满足,这些点动起来之后会在某个时刻全部静止。
\(n\le 18\)。
Sol
妙妙题。
合并让人主观上感觉是很好的, 因为他们合并只会干扰他们两个点,其他点不受影响。但是只知道这个好像没什么用。需要一个更好东西来刻画往哪边运动。
令 \(p_i\) 为前缀异或和,令 \(p'_i\) 为异或和异或上 \(Z\),题目中有一个重要的性质就是权值恰好是一个排列,这就意味着 \(p_i=suf_{i+1}\) 那么就有一个点的 \(L_i=p'_{i-1},R_i=p'_{i}\)。这样就可以把 \(L,R\) 合并在一起判定,观察两个点,假如是 \(i,i+1\) 相撞的条件:\(p'_{i}\ge p'_{i-1}\and p'_{i}\ge p'_{i+1}\) 且两个不等号不能同时去等(否则就不动了)。合并意味着什么?相当于只是把 \(p'_{i}\) 丢掉。这是非常优美的,相当于每一次把一个“峰顶”砍掉,而且砍的顺序并不重要,砍到看不了为止。此时序列一定是一个单谷序列,谷左边都往左运动,右边往右运动。都不运动当且仅当,所有的元素都 \(=Z\)。
这也就意味着,满足条件当且仅当,\(\min p'=Z\)。显然 \(p'_{2^n-1}=Z\),也就是说对于其他的要满足 \(x\oplus Z\ge Z\)。考虑 \(x\) 的最高位(最高有 \(1\) 的位置),发现这个最高位对应的 \(Z\) 的位置不为 \(1\) 是 \(Z\) 满足规定的充要条件。充分:不为 \(1\) 那么 \(Z\) 异或之后一定会变大,因为 \(Z\) 再高的位置不影响;必要:如果不为 \(1\) 那么 \(Z\) 异或之后一定变小,同样因为前面不影响。
LOJ2398
题面
交互,有一个位置的无向联通图,每次询问形如 \((a,b,S)\) 交互库会回答 \(S\) 的导出子图中 \(a,b\) 是否相连,在 \(45000\) 次内求出来这个图。
\(n\le 1400,m\le 1500\),保证每个点的度 \(\le 7\)。
Sol
第一反应是简单的 \(n^2\) 做法。
第二反应是可以维护一个已经知道的图形状的联通子图 \(S\),然后考虑新的一个点 \(x\),如果 \(x\) 和 \(S\) 直接连通,那么可以通过某种二分的方式确定具体联通哪些点。至于找到一个联通的点是否也可以二分?
这个直觉是极为正确的,下面讲正解。
维护 \(0\) 所在的连通块,然后按照上面的思路,问题有两个部分:
- 知道 \(x\to S\) 直接联通,怎么样二分出来具体有哪些点?
我们希望用某种方式排出来所有的点,使得每一次询问一个 \([0,i]\) 的所有点的导出子图中 \(0\to x\) 是否联通。如果联通那么可以让 \(i\) 变小即锁定 \(i\) 与 \([0,i]\) 中其中一个点直接相连,反之 \(i\) 变大,这样的一种单调性。发现这就其实在要求,所有的前缀中所有的点必须联通,那么一个 dfs 序就是不二之选(或者 bfs 序)。
- 知道 \(x\not\to S\),怎么样找到一个 \(y\to S\)?
令 \(T\) 为 \(S\cup \{x\}\) 的补集。我们可以通过类似上面的方法,找到一个在 \(x\to S\) 链上面靠近 \(x\) 的第一个点。具体的,我们不需要一个真的序列,对于 \(T\) 按照任意序列排序,只要找到一个 \(y\) 满足 \(y\) 的前缀所有点 \(\cup\{x\}\cup S\) 的导出子图 使得 \(0\to x\) 即可,因为这意味着 \(y\) 必定在路径上。
学校电脑突然死机了,可能是我跑的东西有点多导致的。生气。
LOJ2846
题面
平面上有 \(k\) 个点,第一个在左下角为 \((1,1)\),最后一个在右上角为 \((n,m)\)。定义两个点的距离为 \(2^{Chebyshev}\),即 \(2\) 的切比雪夫距离次方,切比雪夫为 \(\max(|x-x'|,|y-y'|)\)。求 \((1,1)\to (n,m)\) 的最短路。
\(n,m,k\le 10^4\)。
Sol
首先注意到这个题计算两个点的距离加和是比较大的,即使用 bitset 也是 \(\dfrac{n}{\omega}\)。
口胡环节,直观上感觉如果从左下角走到右上角,如果这个矩形当中有点,那么先经过那个点一定不劣。
这个结论是比较正确的,但是需要将其应用。有引理,如果以当前在的点为原点建立直角坐标系,那么下一个点一定在某一个象限或者坐标轴的某一个正负方向的最近的点。这样看起来只需要建边为 \(8n\) 个,但是在一个象限当中可能有多个点距离相等,因此复杂度还是会劣化。
注意到每一次建边是连接一个 \(L\) 形区块的东西,也就是说形如固定 \(x\) 然后 \(y\) 在一个范围内或者固定 \(y\) 然后 \(x\) 在一个范围内的。考虑线段树优化见图即可,复杂度 \(\dfrac{n^2\log n}{\omega} \log^2n\),但是跑不满。
CF354D
题面
一个 \(n\) 的正三角形,第 \(i\) 行有 \(i\) 个格子。有两种操作:
- 选择一个格子用代价为 \(3\) 将其染黑
- 选择一个底边在正三角形底边的小三角形,将其染黑,代价为点数 \(+2\)。
给定 \(m\) 关键点,求把所有关键点都染黑的最小代价。
\(n,m\le 10^5\)。
Sol
只用第一个操作,代价为 \(3m\),因此第二个操作选择的底边长度最多为 \(\sqrt{6m}\)。者提供了很好的 dp 复杂度。
考虑按照斜对角线来 dp,即对应的 \(x-y=k\) 的斜线。显然对于一个斜线我们只会用 \(2\) 操作染色其一个前缀的点,后面都是暴力染色的。这个性质是优秀的,令 \(f_{i,j}\) 表示第 \(i\) 个斜线,前缀染色为 \(j\) 的最优解,令 \(c_{i,j}\) 表示这一个斜线位置 \(>j\) 位置有多少个黑点,那么有:
要么延续要么新开一个,当 \(j=0\) 的时候特判。后面一个用后缀 \(\min\) 维护一下即可。答案就是 \(\min f_{n,k}\)。
P6575
题面
给定无向图,定义 \(f(S)\) 为 \(S\) 里面所有点连向这个集合外点的边数。将图分成 \(S_1,S_2\dots\) 满足:
- 每一个点恰好在一个集合里面
- \(f(S_i)\le q\)
- \(|S_i|\le p\)
构造方案,可能无解。\(n\le 2500,p+q\le 15\)。
Sol
人类智慧,这个真的口胡不出来。
首先,题目允许枚举出来包含任意一个点是否有合法的 \(S\) 包含这个 \(S\)。
考虑当前的集合为 \(S\),\(S\) 连向一些点,可以把这些点分为两类,\(T_1\) 表示这些点已经钦定不加入 \(S\) 当中了,\(T_2\) 表示未确定。那么每一次就是在 \(T_2\) 里面选择一个点然后加入 \(T_1\) 或者 \(S\)。会发现无论怎么样操作,要么会让这个集合大小 \(+1\) 要么会让 \(f(S)+1\)。也就是说,最多往下递归 \(2^{p+q}\) 步。因为有题目中的限制。
这一部分复杂度 \(\mathcal{O}(n\times 2^{p+q})\),这里其实已经解决了无解的问题了,为何这么说?
Lemma:如果 \(A,B\) 合法,那么 \(A/B,B/A\) 其中至少有一个合法。
令 \(C=A\cap B\),令 \(A/B\to C\) 中有 \(a\) 条边,同理令 \(b\),令 \(C\) 连向 \(\overline{A\cup B}\) 有 \(c\) 条边。观察 \(A/B\),\(p\) 限制一定满足,且 \(\Delta q=a-b-c\) 对于 \(B/A,\Delta q=b-a-c\),这两者其中必定有一个 \(\le 0\),因此必定有一个合法。
这就简单了,只需要对于所有的集合 \(\mathcal{O}(n^2)\) 循环一遍,处理掉不合法即可。
需要一定程度的卡常,主要是快速判断不合法。
CF1770F
题面
给定非负整数 \(n,x,y\),对于所有满足 \(\sum_{i=1}^n a_i=x,\text{OR}_{i=1}^n a_i=y\),的序列 \(\{a_n\}\)。求 \(\bigoplus_{i=1}^n a_i\) 的异或和。
\(n\le 2^{40},x\le 2^{60},y\le 2^{20}\)。
Sol
非常人类智慧,不论是用 Lucas 转化还是范德蒙恒卷积来化 \(\sum\) 的条件。
全部情况的异或比较少见,稍微想一想就会发现,如果 \(n\bmod 2=0\) 的时候,一个序列如果不是回文序列那么其翻转过来的序列就会和其抵消。如果是的,那么就自己的异或和为 \(0\)。那么奇数的情况是类似的,如果抛开来第一位那么剩下的部分就是一个同样条件的子问题,因此答案为 \(\oplus a_1\)。
只需要考虑为奇数的情况,枚举 \(a\) 每一位对于答案的贡献,假设枚举第 \(i\) 位,首先显然要满足 \(y\) 的第 \(i\) 位有值,直接算或和为 \(y\) 不好算,简单容斥一下,令 \(f(y)\) 表示答案为 \(y\) 子集的答案,则 \(ans=\sum_{z\subseteq y}(-1)^{|y|-|z|}f(z)\)。想到这里只需要一般的计数水平,观察到我们只需要知道 \(ans\) 的奇偶性,因此 \(ans=\sum_{z\subseteq y}f(z)\),只需要考虑 \(f(z)\) 为多少:
这个看起来是很绝望的,但是只需要稍微转化,根据 Lucas:
转化得到
枚举 \(z\) 即可,得到 \(f(y)\) 反推回去得到答案。
ARC148F
题面
造计算机,令 \(m=998244353,M=10^9+7\),可以计算加法,乘法,和模 \(m\)。所有是 64 位整数运算。求 \(ab\bmod M\)。
Sol
蒙哥马利算法:
记 \(m^{-1}\) 表示 \(m\) 在 \(\bmod M\) 意义下的逆元,\(M^{-1}\) 为 \(M\) 在 \(\bmod m\) 意义下的逆元。
令 \(\lambda =(m\times m^{-1}-1)\times M^{-1}\bmod m\)。这样就有 \(a(\lambda M+1)\equiv 0\bmod m\)。
这对于算 \(a\times m^{-1}\bmod M\) 很有帮助。注意到 \(a\lambda M\bmod M=0\),那么 \(a\times m^{-1}\bmod M=(a\lambda M+a)\times m^{-1}\bmod M\) 因为前面的东西可以整除,也就是说可以直接计算 \(\dfrac{a\lambda M+a}{m}\),即保证整除了,除法可以直接逆元(因为 \(m\) 是奇数)。
但是有问题,这里最后没有办法直接 \(\bmod M\),只是算出来了一个数值,而不是具体的数。到但是注意到这个数值不是随机的,是有上界的,如果多除几次 \(m\) 就可以缩小到 \(M\) 以内了,这个“几次”就是 \(\log_m(a)\) 次。
因此,可以让 \(ab \div m \times m^4 \div m\div m\div m\)。