Hey Gift:想让流星能够实现幸福的愿望
Jeremy Sp @Track. 1: greedy
随机训一点思维题。打 \(^*\) 的是自己做出来的。
*CF1866D Digital Wallet
略微反套路。 谁告诉你贪心题单都是纯贪心的。 草没看到 \(K\le 10\),求意义。
考虑 dp,\(f_{i,j}\) 表示前 \(i\) 列,现在用到了末尾以第 \(j\) 列结尾的窗口去选取元素。容易证明,在一个列的前缀中选取一定也用到了一个前缀的窗口,这保证了 dp 的正确性。
考虑 \(j\in[i,i+K-1]\),故状态数是 \(\mathcal O(mK)\) 的。
考虑转移。一种是向后挪动一个数而不使用新窗口,另一种是在当前列选择若干个,后推窗口前缀。显然后者要选前若干大来转移。
直接朴素写,时间复杂度 \(\mathcal O(mK\min(K,m))\)。
CF922F Divisibility
兄弟我怎么会做乱搞猜猜猜啊。
考虑这种题为什么难做:每个数都有双重影响,一个是作为约数,一个是作为倍数。遇到这种很难下手的问题,我们尝试对于难处理部分进行猜测,减小问题规模和复杂度。
容易想到的是,如果我们确定了一个集合包含 \(\{1,2,3,\cdots,n\}\),那么对于 \(>\left\lfloor\frac{n}{2}\right\rfloor\) 的部分就只有作为倍数的影响,我们每次删去一个这样的数 \(x\),只会让现有的对数减少 \(d(x)\)。
Conclusion. 找出第一个 \(s=\sum\limits_{i=1}^m d(i)-1\ge k\) 的 \(m\),从这里开始减小 \(s-k\) 一定可以做到。
Proof. 考虑 \(s-k\le d(m)\),而根据质数密度,\(\frac{m}{2}\) 到 \(m\) 这一块大概有 \(\frac{m}{2\ln m}\) 个质数。所以 \(m\) 足够大(事实上,根据题解,这个界只有一百多点)的时候用质数就可以填满。\(m\) 较小的时候打表也可知。
现在考虑怎么用这些 \(d\) 凑出 \(s-k\)。由于 \(s-k\) 非常小,所以我们可以直接背包完成。当然,由于 \(m\) 较大的时候只需要使用质数每次减 \(1\),而 \(m\) 较小的时候要凑出的 \(s-k\) 很小,小块也非常非常多,所以从大到小扫一遍,能塞就塞也可以通过。
CF1009G Allowed Letters
被自己蠢笑了。
考虑贪心,压力给到判定。相当于我们知道一个桶,还有后面的数的选法集合,问能不能整出一个完美匹配。
可以网络流并用费用代替第一步,然而复杂度起飞。考虑还是硬贪,判定完美匹配想到 Hall 定理状物。
考虑后面的左部点虽然很多(包含了后缀的所有位置),但是右部点本质上只有 \(6\) 个(虽然严格完美匹配要把点拆开,但是根据 \(S\le N(S)\) 的条件,我们把每种点选满对条件是不劣的)。所以暴力枚举右部点子集 \(S\),考虑 \(N(S)\) 的大小为后缀中可选集合 \(T\) 满足 \(T\cap S\neq \emptyset\) 的个数,做一遍后缀和即可。
时间复杂度 \(\mathcal O(n2^{\Sigma}\Sigma)\)。
题解有一个比较离谱的 \(\mathcal O(n\Sigma^2)\) 做法,看不明白。
*CF1307E Cow and Treats
感觉不是很难啊。真有 *2500?
考虑算出某头奶牛从左边或者右边进去会停在的位置 \(lpos_i,rpos_i\),一眼得出几个性质:
- 同一种甜度,一侧只能选择一只。
- 在上述基础上每种甜度彼此独立。
- 一个解合法的充要条件是,假设左侧选择集合 \(S\),右侧选择集合 \(T\),则 \(\max\limits_{i\in S} lpos_i<\min\limits_{i\in T} rpos_i\)。
证明都很简单。
现在考虑怎么解决问题。先考虑解决第一问。
由于不存在两个不同的 \(i,j\) 使得 \((f_i,h_i)=(f_j,h_j)\),所以不会存在两个相同的 \(lpos\)。于是我们不妨钦定左边一定有牛,然后枚举 \(S\) 集合的最大值 \(mx=\max\limits_{i\in S} lpos_i\),考虑在钦定选择这头牛的情况下,剩下最多可以选择多少头牛。
此时每种甜度会产生三种有贡献的牛:
- 同时可以放在两边的,即满足 \(lpos_i\le mx\land rpos_i>mx\) 的牛。
- 只能放在左边的,即满足 \(lpos_i\le mx\land rpos_i\le mx\) 的牛。
- 只能放在右边的,即满足 \(lpos_i>mx\land rpos_i>mx\) 的牛。
数出三种牛的数量,每个甜度单独做,能在两边都放上就在两边都放上即可。
用这个做法获得最大值之后,数数也并不困难。每种甜度的每类牛都是本质相同的,先计数每种甜度选出两头或一头的方法,再全部乘起来即可。注意方案中依然钦定了左边一定有牛,但有可能左边不放牛,把左边有牛右边没有牛的方案乘以 \(2\) 对称过去数到即可。
可以优化到单 log。
CF884F Anti-Palindromize
技不如人,想到了费用流还是不会这个套路。
考虑如果没有 \(a_i\ne a_{m-i+1}\) 的限制,我们的问题用网络流刻画是相当简单的。每个字母一个点表示可选集合,连向每个位置进行一个匹配即可。
然而这样没有处理我们 \(a_\ne a_{m-i+1}\) 的限制。我们考虑在从字母走向位置的过程中避免同一字母走向对应位置。不妨先开 \(\frac{n}{2}\) 个点表示对应位置的限制,我们勒令每个字符进入匹配环节之前必须经过这个点产生限制,连接一条容量为 \(1\) 的边即可。然后考虑这样间接匹配怎么设置费用:由于每一对填入的新字母是不同的,所以不会产生填入的字母抢同一个位置的情况,于是费用设置为和自己相同的位置中权值较大的那个位置的权值,跑一遍最大费用最大流就行了。
然而这个题有个贪心做法,而且感觉并不是很困难。T^T
考虑让 \(t=s\),我们使权重尽量少地扣掉不合法的地方。找出所有 \(m\) 对 \(s_i=s_{n-i+1}\),这 \(m\) 对中每一对都至少要换走一个出去。
考虑这其实类似于一个匹配问题。我们选择两个字符不相同的对匹配,取两对中都权重较小的位置交换即可。
考虑绝对众数定理,如果不存在绝对众数,我们直接两两匹配就可以内部消化完成,这样显然是最优的。
如果存在绝对众数,那么我们仅仅凭借内部消化无法达到目的,我们要从外面找 \(s_i,s_{n-i+1}\) 都不是绝对众数字符的对和这里面交换。显然我们从这些位置中选择较小位置最小的前几个就好了。
*CF1073F Choosing Two Paths
简单的题目。
考虑先最大化交。容易发现任取两个度数 \(\ge 3\) 的点就能构成一个可能的交,这也是交非空的充要条件。
交为空的 corner case 为一条链,此时直接把链随意掰成两半即可。
考虑从叶子开始拓扑排序,删掉所有父亲度数小于 \(3\) 的叶子。最后再删掉一层叶子,此时所有的叶子都是度数大于等于 \(3\) 的点,显然我们的最大交就是这棵树的直径。
考虑我们可以把答案拆成三部分:直径和两个叶子在原树的子树直径(因为要最大化链长和,选子树直径显然是最优的)。于是每个叶子上挂着一个权值 \(w_i\) 表示其子树的原树直径,在所有直径当中找 \(w_i+w_j\) 最大的一个即可。这可以用设置直径中心为根轻易完成。
实际上这个有一个颇为简单的实现:我们直接把其他点的点权设置为 \(+\infty\),然后跑带权直径即可。(Sponsored by SA)
CF1685C Bring Balance
结论题怎么玩?! 好像还是挺套路的,不知道为什么没有往这方面想。
Conclusion. 任意括号串只需要翻转不超过 2 个区间。
发现这个还不够做出这题,我们考虑它怎么证明。
Proof.
由于整个串的和是 \(0\),我们实际上只是希望串的前缀和恒为非负。
构造性地,取前缀和最大值 \(a_x\),我们反转 \([1,x],(x,2n]\)。
此时 \([1,x]\) 中的前缀和 \(a_j\) 会变为 \(a_x-a_{x-j}\),显然这个数大于等于 \(0\)。\((x,2n]\) 中的前缀和 \(a_j\) 会变为 \(a_x+a_{2n}-a_{2n-(j-x)}\),由于 \(a_{2n}=0\),所以这个数也大于等于 \(0\)。
QED.
于是只需要判断是否只需翻转 \(1\) 个区间。不妨设这个区间为 \([l,r]\),那么我们希望 \([1,l)\) 中前缀和 \(\ge 0\),\(i\in[l,r)\) 中有 \(a_{l-1}+a_{r}-a_{i}\ge 0\),\([r,2n]\) 中前缀和 \(\ge 0\)。
转化一下条件。我们只需取两个不同的 \(i,j\in[0,2n]\),使得 \([1,i],[j,2n]\) 中的前缀和 \(\ge 0\),\((i,j)\) 中间的前缀和都 \(\le a_i+a_j\) 即可。显然 \(i\) 在一个前缀中,\(j\) 在一个后缀中,我们拿出两个缀的最值出来检验一下就完了。
时间复杂度 \(\mathcal O(n)\)。
*CF725E Too Much Money
首先感性地,容易想到我们只需要多加一枚硬币就足够了。
Proof.
假设我们加了两枚硬币 \(a,b\),且都被用到了,不妨钦定 \(a\ge b\),那么在使用 \(a\) 之前,我们存在这样一个时刻满足值 \(\ge a+b\) 并且下一步计划是选 \(a\)。那么我们一定可以放入 \(a+b\) 达成相同的效果。
考虑枚举它,压力给到快速判定。考虑合并相同面值的硬币,由经典结论我们最多选择 \(\sqrt c\) 种不同的面值,而在桶里面向前找到第一个可以使用的面值是简单的,于是可以 \(\mathcal O(c\sqrt c)\) 解决。
*CF1867F Most Different Tree
考虑先找到一个最小的优结构。我们不妨从 \(1\) 个点的有根树开始按照点数从小往大搜,搜到第一个最小的可以避免出现在树 \(G\) 中的结构。
由于这个结构不存在于 \(G\) 中,我们把剩下的点挂成一条链在它的根上就行了。
容易证明这是最优的。
Proof.
在这个方案中,假设这个结构的大小为 \(siz\),那么 \(P(G')\) 中有 \(siz-1\) 个元素在 \(P(G)\) 中可以找到。
假设存在一个不使用这样结构的方案 \(T\)。取出这个 \(T\) 中最小的一个子树,满足这个子树在 \(P(G)\) 中无法找到。由于没有使用大小为 \(siz\) 的结构,所以这个子树的大小一定 \(>siz\)。
由这个子树的最小性,它内部的所有子树都在 \(P(G)\) 中可以找到,所以它至少有 \(siz\) 个元素在 \(P(G)\) 中可以找到,并不是最优的。
然后考虑实现上,我们要搜出前 \(10^6\) 棵无标号有根树。根据 A000081,我们粗略要搜到 \(n\le 15\)。
直接搜树很不方便,我们知道括号树恰好可以和无标号有根树一一对应,所以我们考虑搜括号串。我们要求每对括号里的子括号结构按照字典序(或者某种偏序,比如搜出来的时间戳)排布即可 \(\mathcal O(ans)\) 搜出。
*CF1238G Adilbek and the Watering System
感觉就是 P1016 [NOIP 1999 提高组] 旅行家的预算 加强版的一道题。
考虑先按照时间排序扫描时间,维护一个二元组可重集合,表示当前水箱里面水的升数和单位价格。每次我们在一个时间段内浇水,我们需要优先花掉价值比较低的水。
然后考虑怎么加入朋友带来的水。首先水箱中所有单位价格超过它的水是不优的,我们尽可能多的把这些水扔掉。尽可能多的意思是说,如果水箱中的空间足够大,就暂时保留这些水,避免之后因为水不够倒闭;如果不够大,就把这些水扔掉,用新的便宜的水来替换它。
显然这样做是最优的。暴力维护,由于每类水至多进出集合一次,复杂度 \(\mathcal O(n\log n)\)。
P7962 [NOIP2021] 方差
被 dp 套路打烂了。/dk
考虑这个操作就是套路的交换差分,现在我们可以任意排列差分序列。
回到方差的组合意义,容易感性地理解到我们希望差分序列是单谷的,这样数字会尽量地均匀。实际上这个结论是正确的,证明见此。
套路地,考虑把差分从小到大排序,我们从差分最小的地方开始往左右扩展两个序列,最小化差分 \(n\sum\limits_{i=1}^n a_i^2-(\sum\limits_{i=1}^n a_i)^2\)。显然需要 dp,不妨记 \(f_{i,j}\) 表示前 \(i\) 个差分值,\(a\) 的和为 \(j\) 的最小平方和。
考虑放左边,此时相当于整个数组被拔高 \(d_i\)。所以:
考虑放右边,记 \(s_i\) 为排序后 \(d_i\) 的前缀和,这个比较显然(注意 \(j\) 是 \(a\) 的和,不要用 \(j\) 转移):
在这里,初值是 \(f_{1,0}=0\),其余为 \(+\infty\)。而答案状态是 \(f_{n,?}\)。
现在你获得了一个 \(\mathcal O(n^2V)\) 的做法,不足以通过本题。但是状态是缺一不可的,于是考虑枚举上界。注意到,开头 \(d_i=0\) 的部分是无意义转移,所以我们删去所有 \(d_i=0\),这样差分数组只剩下 \(\min(n,V)\) 个数,时间复杂度 \(\mathcal O(\min(n,V)nV)\),可以通过。
实现上需要滚动数组。
P7916 [CSP-S 2021] 交通规划
一眼把所有黑点连起来到 \(S\),白点连起来到 \(T\),这部分是钦定掉的,容量设为 \(+\infty\),然后跑一遍裸的最小割,可以获得 \(65\) 分。据说当年 Dinic 卡卡常数能过。
考虑平面图最小割等于对偶图最短路,这是容易理解的,因为我们在平面上的一个割集就相当于在对偶图上打通一些平面,这在对偶图上体现为路径。我们把 \(S\) 和 \(T\) 用一条 \(0\) 权边连起来,多出现了一个平面 \(S*\),不妨设无界面为 \(T*\),那么进一步地,最小割刻画为对偶图上一个包含 \(S*,T*\) 的最小环。所以我们拆去这条边(仅创建平面),最小割就是对偶图上 \((S*,T*)\) 的最短路了。
对于网格图,我们让右上两侧的平面连给 \(S*\),左下两侧的平面连给 \(T*\) 可以达成类似的效果。
回到本题,我们可以用这样的方法解决 \(k=2\),因为这样我们可以直接让 \(S\) 和 \(T\) 分别为输入的两个黑点/白点,直接进行对偶图最短路。\(k>2\) 的问题在于,一旦我们搞出超级源点和超级汇点,图就不是平面图了。
考虑为啥不是平面图了:当我们出现了黑白黑白这样的连续段的时候就会交叉。这启发我们放到连续段上考虑。
我们知道,连续段之间的部分是一定要割开的,但我们不会主动去割开连续段内部的部分(当然,为了割开连续段之间的部分,有可能最后还是要内部割开,不过这样的贡献应该算在割开连续段之间部分的贡献里面,而不是看作我们割开了连续段内部)。
于是考虑答案形态,由于整个东西排布在一个环上,所以割开的部分一定是偶数个,最终答案一定形如这些部分两两配对地割开,每种配对的贡献计算可以套用 \(k=2\) 处的做法。之后只需考虑如何配对。
这里其实有一点证明细节,但是容易感性理解到不合法的答案都是不优的配对方案。
显然,相交配对的割可以完全用一个包含的代替,所以配对只可能包含或者相离。\(\mathcal O(k^3)\) 区间 dp 它即可。
QOJ8085. Bulbasaur
依旧妙蛙种子/.
首先有个显然的做法是,我们直接把两层点拿出来跑最大流,但是这不对,因为我们不允许点相交,所以还要拆一下点。
然而时间复杂度倒闭了。
考虑最大流非常难以刻画,我们转成最小割。于是就是要割掉最少的点让两层点不连通。
假设我们知道两层点 \(l,r\),显然考虑状压 dp 它。\(f_{i,S}\) 表示现在 dp 到第 \(i\) 层,只有 \(S\) 这个点集依旧和 \(l\) 层连通,我们要的就是 \(f_{r,0}\)。
现在考虑怎么对所有子段求和。不妨枚举 \(r\),我们希望知道所有答案的分界点 \(l_0,l_1,\dots,l_k\),显然这些分界点依次递增——越近割得越多。
所以考虑交换刚刚那个 dp 的答案和状态,\(f_{i,j,S}\) 表示第 \(i\) 层,割掉 \(j\) 个点,当前第 \(i\) 层可达性状态为 \(S\) 的最大 \(l\)。
转移考虑枚举前一层连通的点集 \(S\),算出它走到这一层连通的点集 \(T\),枚举 \(T\) 的子集表示如何割 \(T\) 即可做到朴素的 \(\mathcal O(nk4^k)\)(注意这里不是枚举子集,因为可能有相同的 \(T\) 来自不同的 \(S\))。
显然可以改为一个高维前缀和的形式。\(S\) 维的变化就是普通的子集,可以用普通的高维后缀 \(\max\)。只不过我们还要维护 \(j\) 维的贡献,它是一个和子集 popcount 相关的东西,显然可以在高维后缀 \(\max\) 的同时一并维护。
滚一下数组就可以通过了。时间复杂度 \(\mathcal O(n2^kk^2)\)。
P7116 [NOIP2020] 微信步数
好没意思的题,随便写个暴力有 \(80\) 分。
一个显然 \(\mathcal O(k^2w)\) 的暴力是,我们把所有维度所有点走出去的时间用分类讨论求出,然后相当于每个维度取一个点,所有取法的 \(\min\) 之和。为了实现这个,我们需要对 \(\mathcal O(k)\) 个长度 \(\mathcal O(w)\) 的数组排序然后归并。但是我们注意到每个维度的点的走出时间是单峰的,所以折半归并就能不带 log 排序了。
考虑观察每一维上走出时间的性质。可以发现,如果设完整 \(n\) 步这一维上的偏移量为 \(s_i\),最小和最大偏移量为 \([L_i,R_i]\),那么除了第一轮会导致前后一部分点直接倒闭(\(j+R_i>w_i\) 和 \(j+L_i<1\) 的部分),中间的点的模式都是相似的。因为中间这些点都会一轮一轮地走 \(|s_i|\) 步向前或者向后挪,直到某一轮中这个位置加上 \(L_i\) 或者 \(R_i\) 会走出去为止。
考虑“前后一部分点”的数量显然是 \(\sum R_i-L_i=\mathcal O(n)\) 的,我们先不管它们。
对于 \(s_i\ne 0\) 的维度,中间这些点一定每 \(|s_i|\) 地一循环,可以写成 \(nx+a_i\),其中 \(a_i\) 是头或尾那些特殊点的靠中间的 \(|s_i|\) 项的值,因为中间每个点每轮恰好往外扩散 \(|s_i|\) 步。
现在考虑怎么计算答案。我们原本的算法是枚举 \(\min\),考虑钦定这个位置做 \(\min\),算出方案数再乘 \(\min\)。套路地,钦定不好做,所以我们把贡献摊开,枚举从第二轮开始所有的时间 \(T\),考虑有多少选法使得我们选出一个向量每一维都大于 \(T\)。容易发现这就是:
这个 \(x\) 的位置让我们不太好控制上界,我们换个枚举 \(T\) 的方式,先枚举轮数 \(i\) 再枚举步数 \(j\),那么原来的 \(T\) 就是 \(ni+j\)。再显然容斥一下后面那个和式,设 \(r_i\) 表示第 \(i\) 维第一轮结束之后剩余的点数。
因为 \(a\) 数组的值域是 \(\mathcal O(n)\) 的,所以我们也可以轻易求出后面那个前缀和。于是答案是:
那么 \(i\) 的上界就好办了。设 \(LM_j=\min\limits_{p=1}^{k}\left\lfloor\frac{r_p-f_j}{s_p}\right\rfloor\),我们有答案是:
内层积只有 \(k\) 项,这种一次多项式乘法,直接暴力分治,得到一个关于 \(i\) 的 \(k\) 次多项式 \(F(i)\)。对于它的每一项,本质是一个自然数幂和。在本题中,\(k\le 3\) 用公式,\(k>3\) 暴力乘就好了。
Jeremy Sp @Track. 2: dp
随机训一点思维题。打 \(^*\) 的是自己做出来的。
CF677D Vanya and Treasure
很无敌的优化!这个题用 ds 嗯写的才是坏文明!
考虑一个显然的 \(\mathcal O(n^2m^2)\) dp:\(f_{i,j}\) 表示走到 \((i,j)\) 的最小步数。那么我们每次需要在相邻权值之间进行一个 \(\mathcal O(c_ic_{i+1})\) 的转移,其中 \(c_i\) 表示 \(i\) 权值的个数。
卡掉这个东西的方法很显然,我们取 \(c_1=c_2=\frac{nm}{2}\) 就好了。
但我们发现,当 \(c_ic_{i+1}>nm\) 时,我们不如把所有 \(i\) 的点丢进队列跑多源最短路,复杂度是 \(\mathcal O(nm)\)。考虑到 \(\sum c_i=nm\),而为了产生 \(c_ic_{i+1}>nm\),两个当中必然有至少一个超过根号的数,所以只有根号次多源最短路。
然后考虑 \(c_ic_{i+1}\le nm\) 的情形。实际上可以证明,此时我们直接跑老暴力复杂度是正确的。
Proof.
感性理解吧。
于是总时间复杂度 \(\mathcal O(n^3)\),可以通过。
注意初始权值非 \(0\) 的多源最短路比较特殊。需要先从最小的点开始跑,过程中做到对应权值的时候再把后面的点加进去,这样才能维护队列的单调性,这个排序之后双指针就好了。
*CF1499E Chaotic Merge
先考虑整个串怎么做,考虑 \(f_{i,j,0/1}\) 表示取到 \(x_i\) 和 \(y_j\),上一把取的是 \(x_i\) 还是 \(y_j\) 的方案数,那么转移只需考虑取 \(x_{i+1}\) 还是 \(y_{j+1}\),是简单的。
现在考虑对所有区间求 dp 值之和。考虑 CF1810G 的 trick,我们发现这些子区间的 dp 唯一的区别就是初值是 \(1\) 的地方不同,转移都是一模一样的。
我们不妨把转移实体化,架在 DAG 上考虑。于是可以发现我们就是要求从所有初值可以为 \(1\) 的点出发,能走到所有点的路径数量之和。直接考虑 \(f_i\) 表示从任意初值为 \(1\) 的点出发走到 \(i\) 点的路径数量,答案就是所有 \(f\) 之和,dp \(f\) 只需使用拓扑排序。
实现时注意细节。因为 \((1,1)\) 的初值实际上可能可以让我们走到 \((3,1),(10,1)\) 等,但是此时 \(y\) 串没有选择所以其实应该不算,要把这种只在一个串里选的抠掉。
当然你也可以这么理解:

*CF641D Little Artem and Random Variable
我们先考虑刻画 \(p1,p2\)。不妨设 \(PA_i,PB_i\) 表示 \(a,b\) 数组的前缀和,\(SA_i,SB_i\) 表示 \(a,b\) 数组的后缀和,由容斥我们知道:
对它们累一下前缀和和后缀和,我们就能知道 \(PA_iPB_i\) 和 \(SA_iSB_i\),不放记为 \(P_i\) 和 \(S_i\)。
现在考虑利用这两个式子。由于 \(PA_i=1-SA_{i+1}\),我们有:
显然我们可以用如上方式得到所有 \(SA_{i}+SB_{i}\)。差分之后就能得到 \(a_i+b_i\)。
这提示我们可能需要解个方程。我们继续尝试构造 \(a,b\) 之间的关系。不妨考虑 \(S_i-S_{i+1}\):
根据这个式子,我们显然可以知道 \(i=n\) 处的 \(a_ib_i\)。显然考虑往前递推,那么这个东西是一个关于 \(a_i,b_i\) 的一次式。考虑到我们还知道 \(a_i+b_i\),那么换元解一元二次方程即可。
解出来的方程有两个根,我们总是把同样符号的给到 \(a_i\) 或者 \(b_i\) 就行。原因暂时说不清楚。
*CF1083E The Fair Nut and Rectangles
斜率优化板子,单调栈上二分然后完了。
CF920D Tanks
被 Hack 降智了。
我们显然更加关心 \(a_i\bmod k\) 的值,因为我们无论怎么舀“表面”都无法改变模 \(k\) 的值,只有舀到最底下的时候才能舀出 \(a_i\bmod k\)。所以我们显然需要选出一个子集 \(S\) 舀玩来凑齐余数,换句话说这个子集 \(S\) 需要使得 \(\sum\limits_{i\in S}a_i\equiv V\pmod k\)。我们显然可以简单地把这些罐子里的水集中到其中的一个。
显然我们只让余数对上是不够的,因为这个罐子里的水量有可能小于 \(V\)。在保持余数不变的情况下,我们只需要让里面有尽可能多的水,多了再舀出去就好了。考虑把所有在选出这个子集之外的水也集中在一个罐子里,然后我们把那些水的“表面”舀空。
对于固定的子集,这样做显然是最优的。而我们要选出一个最优子集实际上也是简单的:由于子集的余数已经确定,整个集合的余数也已确定,所以选择一个最大化总水量的子集不会对子集外面产生更多不好的影响。
注意实现细节。
*CF1485F Copy or Prefix Sum
钦定每种序列尽可能取 \(b_i=\sum a_j\)。于是我们设 \(f_i\) 表示 \(i\) 处使得 \(b_i\) 起到前缀和作用,可以转移的 \(j<i\) 需要满足不存在 \(j<k<i\) 使得 \(b_k=b_j+sum_k-sum_j\),否则同样的序列 \(b_k\) 也可以作为前缀和位置使用。由于我们的钦定是贪心,所以这种方案不准转移。移项可得,对于每个 \(b_i-sum_i\) 我们都从最后一个位置转移即可。
前缀和优化,时间复杂度 \(\mathcal O(n\log V)\)。
CF1984F Reconstruction
……看错题了,最后临门一脚。
首先注意题目要求我们数的是有多少种 SP 串,不是 \(a\) 序列。
我们不妨考虑先找到整个序列的和。可以发现,整个序列的和一定会在某个断点被记录到,SP 串一定可以找到以下 \(3\) 个情况之一:
- 开头是
S。 - 结尾是
P。 - \(c_{i-1}\) 是
P,\(c_i\) 是S。
所以我们整个序列的和 \(sum\) 实际上只有 \(\mathcal O(n)\) 种,我们可以把它们暴力找出来 check。
然后我们考虑知道和之后怎么做。考虑 dp \(f_{i,0/1}\) 表示前 \(i\) 个位置已经确定,第 \(i\) 个位置是哪种字符的方案数。我们来考虑相邻两种字符产生的限制:
PP:\(|b_i-b_{i-1}|\le m\),SS是类似的。PS:\(b_{i-1}+b_i=sum\)。SP:可以解出 \(a_{i-1}+a_i\),存在一种分配方式让它们的绝对值都不超过 \(m\)。
事实上,如果任意相邻位置的条件都能被满足,我们一定可以找到一个合法的序列。
首先我们明白任何数的限制都一定只能来自于它相邻的两个位置。那么我们不妨考虑答案形态:在确定的 SP 串中,PS 显然无法构成任何限制,所以我们可以把序列从这里切割开成独立的部分。每个部分形如 SSS...SP...PPP,显然我们能够确定性地得知除了中间两对 SP 以外的数,并用 SS 和 PP 加以限制,而中间的两个数确实仅被 SP 限制了和,任意满足约束的构造都能得到一个合法序列。
时间复杂度 \(\mathcal O(n^2)\)。
CF1716E Swap and Maximum Block
败了,怎么还是反应不过来线段树每个节点上可以记录 \(\mathcal O(len)\),或者说 \(\mathcal O(2^{dep})\) 的信息???P10856 【MX-X2-T5】「Cfz Round 4」Xor-Forces 和这题几乎一样,但是都没做出来。
显然一次操作等价于让线段树的一层反转儿子。考虑预处理所有 \(2^n\) 种反转产生的序列的答案。
考虑维护最大子段和我们只需要记录 \(\mathcal O(1)\) 个信息,那么每个节点内部子树的情况合在一起就需要记录 \(\mathcal O(2^{dep})\) 个信息,其中 \(dep\) 是子树深度。显然,这个值等于 \(len\)。
考虑往上 pushup 只需要将对应信息合并即可(显然子树两边对应层的翻转状态应当相同)。
考虑我们最终得到了 \(2^nn\) 个信息,每个信息的产生和维护都是 \(\mathcal O(1)\) 的。于是时间复杂度为 \(\mathcal O(n2^n)\)。
*CF1767E Algebra Flash
考虑一个方案合法的充要条件是任意相邻两个颜色必有一个选上了,而且 \(c_1\) 和 \(c_n\) 必选。不妨连边 \(c_i,c_{i+1}\) 转到图上,那么我们本质上需要求一个要求 \(c_1,c_n\) 必选的最小点覆盖。
任何点覆盖都是独立集的补。所以我们直接转成不准选 \(c_1,c_n\) 的最大独立集。考虑 mitm,我们钦定后 \(20\) 个点的选法,先判定本身构成独立集,然后考虑它们对前 \(20\) 个点的限制——形如一部分点一定不能选上。所以我们在前 \(20\) 个点必须要选一个集合的子集。
显然并不是任何一个子集都可以,因为前 \(20\) 个点也要构成独立集。我们可以预处理前 \(20\) 个点的所有独立集,用高维前缀 \(\max\) 来支持快速查询。
时间复杂度 \(\mathcal O(2^{\frac{m}{2}}m^2)\),写好一点可以掉一只 \(m\),不过没必要。
*CF1327F AND Segments
非常简单的题。显然所有位之间独立,我们拆位即可。之后限制形如一个区间必须全为 \(1\),或者某个区间必须有 \(0\)。类似著名的 ABC262H,设 \(f_i\) 表示第 \(i\) 位为 \(0\) 的方案数,考虑到上一个 \(0\) 中间不能完整包含任何限制区间,故转移来自一个后缀。前缀和优化转移即可。
*CF2021D Boss, Thirsty
有点难,想了一会。
显然这个限制是在说两天的区间必须有交,但不能包含。说白了就是必须有一侧有凸起。
第一反应是考虑设 \(f_{i,j}\) 表示第 \(i\) 天 \(R=j\) 的最大权值和,从前一天的 \(f_{i-1,k},k<j\) 处转移过来,找一个 \(p\le k\) 表示左端点构成今天的区间即可。然而我们发现问题在于凸起不一定在右边,但我们不能从 \(f_{i-1,j}\) 转移过来,这样是否被包含是不明确的。
考虑对左侧维护一个类似的 dp 数组,\(g_{i,j}\) 表示第 \(i\) 天 \(L=j\) 的最大权值和。那么凸起在左侧的情况,我们可以用 \(g\) 来转移 \(f\):枚举前一天的 \(g_{i-1,k},k<j\),再枚举 \(p<k\) 表示左端点和 \(j\) 构成今天的区间即可。
\(g\) 也可以类似的转移。
直接朴素转移复杂度是 \(\mathcal O(nm^3)\) 的,无法通过。
可以发现转移的系数形如 \(p<k<j\) 使得 \(a_p+b_k\) 或 \(a_p-b_k\) 最大,我们只需前缀 \(\min\) 过去即可,时间复杂度 \(\mathcal O(nm)\)。
CF1208F Bits And Pieces
可恶,临门一脚。
考虑转化为对每个 \(i\) 求出 \(\overline{a_i}\ \&\ a_j\ \&\ a_k\) 的最大值。
我们发现,想求在后面是否有合法的一对 \(a_j\ \&\ a_k\) 使得 \(x\) 是它的子集是比较简单的:我们考虑维护 \(f_x\) 表示是 \(x\) 超集的两个不同的数的位置,那么只有当 \(x\) 出现在两个位置中较小的一个之前的时候才能在后面找到这么一对 \((j,k)\)。这个 \(f\) 显然可以高维后缀和求出。
现在问题回到我们的 \(\overline{a_i}\) 上。如果我们暴力枚举 \(\overline{a_i}\) 的子集检查复杂度是 \(3^{\log_2 V}\)(注意这里有一个不合法不优。如果一个数可以找到一对 \((j,k)\),但并不是真实的按位与值,那么一定可以找到一个更大的),无法通过。
不妨考虑按位贪心。因为这个可以找到一对 \((j,k)\) 是具有单调性的,如果某一位上是 \(1\),后面未知的情况可以找到,那么它完全偏序掉了这一位是 \(0\)。所以我们从高位往低位确定即可。
*CF761F Dasha and Photos
可以给刚学前缀和的小朋友做。/kx
考虑答案的构成。两个图案 \(i,j\) 的距离实际上可以看成:
- \(i\) 的那一块,原状变为 \(ch_i\)。
- \(j\) 的那一块,原状变为 \(ch_j\)。
- 抠掉相交部分的两边贡献,增加一个 \(ch_i\to ch_j\) 的贡献。
显然的是,前两者我们都可以用前缀和在 \(\mathcal O(\Sigma nm)\) 时间之内完成预处理。
最后一个实际上也可以。我们大力前缀和一下,维护 \(ch_i\) 在相交的部分当中被还原的贡献和,其他矩阵 \(j\) 在相交部分中被还原的贡献和即可。
*CF1051E Vasya and Big Integers
显然 dp 这个划分。
考虑到长度在 \(|l|+1\) 到 \(|r|-1\) 之间的串显然无需判定,只要下一位上不是 \(0\)(因为要没有前导零)就可以转移。这部分可以用一个简单的前缀和解决,还剩下 \(\mathcal O(1)\) 种转移需要我们单独做:长度恰好为 \(|l|\) 或 \(|r|\) 的。
考虑到等长度的整数比较等价于字典序,所以现在我们相当于要判断文本串的一个子串是否字典序比一个模式串小。我们显然只需找到它们的 LCP,然后判断下一位,LCP 可以用 Z 函数解决。
*CF2122E Greedy Grid Counting
先考虑这个条件的等价条件。我们注意到,每条路径可以由一个点 \(i\) 唯一确定,\(i\) 表示从这个点开始往下走。随后我们发现,假设第一行为 \(a\),第二行为 \(b\),那么从 \(i\to i+1\) 产生的代价差恰好为 \(\Delta=a_{i+1}-b_i\)。
考虑一条 \(b_i>a_{i+1}\) 的路径,显然有一个必要条件是要求它往后调整一个前缀之后,这个前缀不能产生 \(>b_i-a_{i+1}\) 的代价差,否则我们调整过去就比这里优了。我们对所有这样的路径进行此限制,容易发现这也是充分的。
显然这个条件又等价于,对于任意两个相邻的 \(i,j\) 分别满足 \(b_i>a_{i+1},b_j>a_{j+1}\),那么 \(i+1\) 到 \(j\) 中间的前缀代价差都要 \(\le b_i-a_{i+1}\)。这是很好理解的,因为这样完整的每一段代价差(算上端点)都 \(\le 0\),所以每个 \(b_i>a_{i+1}\) 自己后面那一段再之后的限制其实没用。
不妨设 \(f_{i,j}\) 表示做到点 \(i\),当前前缀代价差为 \(j\) 的方案数。转移考虑这一位是 \(b_i>a_{i+1}\) 还是 \(b_i\le a_{i+1}\) 分情况转移即可。
注意第二维是 \(\mathcal O(k)\) 的,因为代价差超过 \(k\) 肯定爆了。所以使用前缀和优化后总复杂度 \(\mathcal O(nk)\),当然如果你不用或者复杂度没分析对也是可以以 \(\mathcal O(nk^2)\) 或者 \(\mathcal O(n^2k)\) 的复杂度通过的。
CF1487G String Counting
我做得有点复杂。思路挺对的但是还是有些暴力了,看来套路见多了思维也要跟上啊。
首先你要注意到这个条件等价于不存在两个相同字符间隔为 \(1\)。据此我们可以进行一个聪明的转化:把奇数和偶数位置分别拆开,两部分是独立的,而两个序列的限制变为要求相邻不相同。
考虑如果没有数量限制我们的问题会非常好做。我们随意地 dp 即可,当然组合也是可以的,答案显然是 \(26^2\times 25^{n-2}\)。
据此我们可以发现那个 \(\frac{n}{3}<c\) 的限制的作用了。它意味着如果我们忽略数量限制,至多只有 \(2\) 种字符超限。
显然是要我们容斥。我们考虑减去所有至少一种超出的方案,再加上有钦定两种超限的方案。
不妨 dp 至少一种超出的方案。可以发现我们的状态实际上不关心超出的字符是谁,我们只关心世界上分为了超出的字符和不超出的字符两种字符,至于实际上谁超出可以在答案处枚举,也可以在答案处钦定它超出。所以设 \(f_{i,j,0/1}\) 表示前 \(i\) 个元素,超出的字符用了 \(j\) 个,上一个字符是否是超出字符。
此时我们聪明的拆开转化的好处就体现出来了。我们只需多判断一下在 \(\frac{n}{2}\) 处不考虑上一个字符的影响,但我们的状态却精简了很多,因为不用记最后两个字符的状态了!
超出两种就很类似了。把刚刚只记一个字符状态的 \(f\) 拓展成 \(g_{i,j,k,0/1/2}\) 即可。
总时间复杂度 \(\mathcal O(n^3+n^2\Sigma^2)\),可以在 \(1\) 秒之内跑完。
毕业照 (matriculate)
好简单的题。。。
我们考虑枚举第一个位置是谁,这样我们可以确定每种字母的段数(所有的相邻不同对,都钦定对右侧的字符产生一个段)。据此又可以确定字母的数量,我们用一个插板就可以把具体的字母映射成一段一段的了。现在我们考虑怎么把段合到一起。
trickily,我们考虑对一个相邻不同对 \(c_1c_2\) 连 \(c_1\to c_2\)(你做过很多后缀连前缀的欧拉路题对吧),这样我们就可以把方案映射到欧拉路,第 \(i\) 次经过某个点就拿走它这种字母分出来的第 \(i\) 段就好了。其实不映射嗯理解好像也可以。
考虑我们之前就已经选定了起点 \(s\),我们用欧拉路判定定理为它找一个终点 \(t\) 即可。当然,如果判定出来没有欧拉路,那么这一块贡献就是 \(0\)。
考虑怎么数 \(s\to t\) 的欧拉路。考虑我们为每个点先随便多重集排列数一个出边顺序(不过其实只有两种边,所以等价于直接组合数)生成所有可能的路,然后斥掉不合法的。
Conclusion. 当且仅当存在一个点的最后一条出边是到 \(t\) 的,构成一个合法的欧拉路。
Proof. 考虑充分性,考虑我们走完这条出边到 \(t\),剩下的步骤一定在剩下两个点之间横跳,与这个点无关,而只存在一个终点,所以最终一定会达到 \(t\),不可能停留在另一个点。必要性显然。
钦定两个点的最后一条出边都不到 \(t\),组合斥掉即可。
P8866 [NOIP2022] 喵了个喵
根据 \(15\) 分做法,我们的策略必然是考虑保留一个空栈来达到消除底部的目的。我们把颜色两两分配到一个栈里,然后来考虑怎么处理多出来那种颜色。
首先如果此时场上存在大小 \(\le 1\) 的栈,那么我们可以直接放进去,改一下特殊牌就行。
另外的办法我们就要考虑怎么利用那个空栈了,因为不能直接无脑放进去。
容易想到我们考虑它到下一张同类牌之间的牌。如果之间所有牌都在消栈顶,我们当然可以把它无脑塞进空栈。否则我们要考虑保留空栈来满足中间消除底部的目的。所以我们产生了一个新的策略:找到第一个中间消底的栈,把它放在那个栈上。
然而这样还是错的,因为我们放上去可能会挡住那个栈顶上的牌。
考虑如果我们没有挡住,那么我们确实可以放上去,之后发生的事情无非是多出来那种颜色换了一个。因为现在多出来的颜色找到了它的栈,而利用我们经营的空栈弹出去那个栈底反而位置被占据了,所以身份交换了一下。
考虑如果挡住了,那么我们转而把这张牌放在空栈上,因为发生了挡住事件,所以我们一定会先消除那个栈的栈顶,再从栈顶消栈底,这样那个栈会变成一个空栈!我们声称那个栈变成新的空栈,它的栈底变成新的多余颜色就好了。
是否挡住只需考虑栈顶牌出现次数的奇偶性,剩下的写的时候努力维护一下各种信息即可。太恶心了。
P8292 [省选联考 2022] 卡牌
好吧我依旧不会做这种塞质数题。
首先显然把 \(n\) 变成 \(V\),因为我们只关心一种数选不选。所以每种数产生 \(2^{cnt}-1\) 的贡献,这样只剩下 \(2000\) 个了。
考虑解决 \(s_i\le 30\)。此时我们直接把 \(30\) 以内的质数压成一个 bitmask,背包一下,查询时枚举超集即可。
trickily,我们现在考虑更大的质数。显然,对于 \(\le 43\) 的 \(14\) 个质数,我们依旧压位,而 \(>43\) 的质数每个数至多有一个,所以可以直接存下来。于是现在我们只需求包含某些大质数,且是某个 \(S\) 超集的方案数。
考虑容斥。容斥大质数非常不方便,我们考虑容斥超集。我们设 \(f_S\) 表示至多包含 \(S\) 当中这些元素的方案数,对于每个 \(S\),我们扫一遍所有大质数,把每个大质数里面是 \(S\) 子集的数量数出来放在 \(2\) 的幂上乘进去即可。特别地,对于钦定的大质数要减个 \(1\),因为不允许贡献空集。
然后高维差分一遍就好了。
一开始以为是所有质数的和 \(\le 18000\),结果是个数和…… 如果知道这点应该也不一定会想不出来了。所以实际写出来有点卡常,可以考虑把 \(43\) 也放进大质数范畴,因为 \(43\times 47>2000\)。
这个题有个 FWT 做法
考虑我们不要容斥。
先考虑没有大质数钦定的情形,这时我们可以直接把每个大质数的方案数(一个多项式,\(f(S)\) 表示小质数形如 \(S\) 的方案数)或卷积起来,最后要求的也就是 \(\forall S\subseteq T,f^*_T\)。
然后考虑有了大质数钦定之后,产生的区别其实也就是 \(f(0)\) 减小了 \(1\)。所以我们可以把 \(\textsf{FWT}(f(S))\) 和 \(\textsf{FWT}(f(S)-1)\) 预处理出来,这样我们每次把所有大质数的 \(\textsf{FWT}(f)\) 点乘起来,最后倒回去做一遍 \(\textsf{IFWT}\) 就可以了。
复杂度和容斥做法是一样的。
CF2143F Increasing Xor
显然操作可以强化到我们对每个数选一个集合异或一个它前面的子集。
不妨考虑线性基。显然前缀只有 \(\log\) 种线性基,假设我们可以把这 \(\log\) 个区间分出来,这样每一块里面能异或上的子集都是一样的。
考虑一个区间里面这些元素都不能够插进它们属于的基里面。换句话说,它们变成一个数的过程实际上一定可以看成是先变成 \(0\),再变成一个能由基合成出来的数。所以我们贪心地考虑,维护 \(x\) 表示上一个区间的最后一个元素,我们把这个区间的最后一个元素设置成对应的基里 \(>x\) 的第 \(r-l+1\) 个可以合成出来的数即可。如果不够了就返回 NO,否则继续做下去。
现在考虑我们怎么划分区间,直接用 ST 表和二分来划分是 3log 的。不妨考虑倒着扫描线,我们尝试用类似前缀线性基的技巧维护 \(l\) 开头的所有基。
CF1861E Non-Intersecting Subpermutations
考虑先把每个序列按在一个数到它最大化段数的方案上去计数。容易发现我们找到这个最大化段数的方法是贪心地每次往后选,能分就分。
于是设 \(f_i\) 表示只考虑前 \(i\) 个位置,贪心过程中有一段是以 \(i\) 为结尾的合法段的方案数。显然最后的答案就是 \(\sum\limits_{i=k}^n f_ik^{n-i}\)。
然后考虑怎么 dp \(f_i\)。如果我们正向计算,从 \(f_j\) 转移过来使得 \((j,i]\) 只有唯一一个以 \(i\) 结尾的合法段,那么我们将涉及另一块容斥,并且最终形如一个半在线乘法卷积,无法通过本题在模拟赛中的任意模数 \(n\le 10^5\) 版本。
我们考虑容斥 \(f\)。我们钦定好最后一块是合法段,方案数为 \(k!k^{i-k}\),之后再减去存在一个合法段和它叠在一起的方案,因为只有这些方案不会取到它。
考虑和它叠在一起的方案首先要由一个 \(j\in[i-k+1,i)\) 转移过来,然后剩下 \(i-j\) 个数在最后一块任选。于是我们减去 \(f_j(i-j)!\) 即可。
这样就做完了,复杂度 \(\mathcal O(nk)\)。
AT_cf16_exhibition_final_e Water Distribution
我蠢蠢的。
考虑答案形态,形如每个点向某些点
简单求和问题
一般困难。
先考虑怎么计算 \(f(x)\)。可以发现,由于所有 \(a\) 中的元素是无交的,所以我们可以把位拆出来独立考虑。换句话说,对于某个元素 \(a_i\),\(x\) 中 \(a_i\) 覆盖的那部分位要么改为全 \(1\) 要么改为全 \(0\),并且所有 \(a_i\) 是独立的,贡献到 \(f(x)\) 就是简单求和。
先不管不覆盖的那些位置。为了计算 \(f(x)\) 的和,我们显然转置问题,考虑每个 \(a_i\) 对所有 \(f\) 产生的贡献。可以发现,假设我们把 \(b\) 中那些数只保留 \(a_i\) 覆盖的位拿出来构成新的数组 \(b'\),那么每个子集 \(T\) 产生的贡献实际上是 \(\bigoplus\limits_{i\in T} b'_i\) 中 \(1\) 和 \(0\) 个数的 \(\min\)。
我们考虑硬做这个问题。求出当前序列有多少个子集的 \(\operatorname{popcount}\) 恰好为 \(x\)。
考虑线性基。我们知道,从长度为 \(m\) 的序列的线性基里面任组合一个子集的出现次数都是 \(2^{m-r}\),其中 \(r\) 是线性基的秩,换句话说也就是 \(2\) 的自由元次方。这样我们的序列就只有 \(30\) 的大小了。
直接枚举子集会 TLE,我们考虑 mitm 之后拼在一起。我们不妨对高 \(B\) 位线性基枚举子集,再对后 \(30-B\) 位线性基也枚举子集,然后考虑两边任意子集异或拼起来的 \(\operatorname{popcount}\)。可以发现,由于后 \(30-B\) 位线性基里面一定没有高位,所以永远不会影响前 \(B\) 位的状态!于是我们不妨合并前 \(B\) 位的状态,维护 \(g_{i,S}\) 表示前 \(B\) 位 \(\operatorname{popcount}=i\),后 \(30-B\) 位为 \(S\) 的方案数。
考虑为了求出所有 \(\operatorname{popcount}\) 的情况,我们不得不对每一个后 \(30-B\) 位的子集再枚举一次所有子集和前 \(B\) 位的后半截拼合来求出完整的 \(\operatorname{popcount}\)。所以我们取 \(B=10\) 来平衡即可。对于更一般的情况,我们显然取 \(B=\frac{1}{3}\log V\) 即可。
还剩一点小问题。考虑没有被任何 \(a_i\) 覆盖的那些位置,我们仍然需要求所有子集的 \(\operatorname{popcount}\) 之和。不过我们没必要使用上面的算法了,我们只需简单地对每一位独立考虑,在所有这一位为 \(1\) 的元素中选择奇数个即可。式子是一个组合数的和式,所有和式加起来只有 \(m\log V\),所以复杂度是对的。
总时间复杂度 \(\mathcal O(n+m\log V+V^{\frac{2}{3}}\log V)\)。
P12300 [ICPC 2023 WF] Tilting Tiles
有趣且简单的题目,想到置换环就没想了……
首先我们发现,当我们把所有方块推到一个角落之后,无论我们接下来怎么操作,对于每个角落来说方块的轮廓都是不会变化的。
然后我们考虑操作实际上只剩下两种:
- 从某个角落出发绕一个环,由于轮廓不变,那么实际上每个点会替换成另一个点,最终将构成一个置换。
- 从某个角落出发绕不出一个环,由于操作可逆(一次 \(op\) 和一次 \(op^{-1}\) 会抵消掉),所以我们实际上只有 \(\mathcal O(1)\) 种情况。
先考虑绕环。可以发现,如果我们从一个角落开始绕环,那么我们永远绕的都是同一种环。因为顺时针和逆时针环是逆运算,同时用两个可以抵消,所以最后只剩下一个。
在此基础上,于是所有的移动方案都可以看成先用 2) 推到一个角落,经过若干相同的 1) 的环,然后再用 2) 推到目标局面的那个角落。由于操作可逆,我们可以暴力两边 2) 推出来的局面,然后只需考虑能否通过固定的一些置换环从一个局面抵达另一个局面。
我们抽出所有置换环,那么实际上它上面发生的事情是一个循环移位,而我们希望通过循环移位让字符串匹配起来。排除不可能匹配的情况是无解之后,由 WPL 推论我们知道,所有整周期都是最小整周期的倍数,据此所有可能的移位步数模最小整周期都是同余的。使用 KMP 做字符串匹配并求出最小整周期即可。
接下来我们考虑判定同余方程组是否有解。如果我们直接用 exCRT 硬做会因为解太大爆掉,但我们可以沿用它的思路——我们判定两两同余方程是否都有解。事实上,这是充要的。
Proof.
必要性显然。
充分性考虑 exCRT 的合并过程,我们归纳它。假设前 \(k\) 个方程合成了一个同余方程 \(x\equiv b\pmod M\),其中 \(M=\operatorname{lcm}(m_1,m_2,\dots,m_k)\),现在我们考虑把方程 \(k+1\) 合并进来,那么我们要求 \(b\equiv a_{k+1}\pmod {\gcd(M,m_{k+1})}\),下面我们证明这可以被两两有解推出:显然,对任意 \(i\le k\),我们必然有 \(a_i\equiv b\pmod {m_i}\)。这显然可以推出 \(a_i\equiv b\pmod {\gcd(m_i,m_{k+1})}\)。
又因两两有解,我们有 \(a_i\equiv a_{k+1}\pmod {\gcd(m_i,m_{k+1})}\)。两者结合我们有 \(a_{k+1}\equiv b\pmod {\gcd(m_i,m_{k+1})}\)。
这样实际上我们得到了 \(k\) 个方程。我们考虑合并这 \(k\) 个方程,结果显然是 \(b\equiv a_{k+1}\pmod{\operatorname{lcm}(\gcd(m_i,m_{k+1}))}\)。实际上我们可以证明,\(\operatorname{lcm}(\gcd(m_i,m_{k+1}))=\gcd(M,m_{k+1})\),对每个质因子考虑即可,结论很显然。
考虑到所有置换环长度之和为 \(\mathcal O(nm)\),而长度相同的置换环一定只保留一个,所以我们实际上只有 \(\mathcal O(\sqrt{nm})\) 个同余方程组,暴力两两枚举判断即可。
CF1781F Bracket Insertion
又写假算去了,没有战胜!
生成方式是固定概率的,我们先把生成方式抛开,计算每种插法出现的概率。
考虑前缀和刻画,那么这个操作就很方便,因为 () 和 )( 两个串的和都是 \(0\),所以它们不会影响任何已有的前缀和,只是说会在中间某处插入一个 \(x+1,x\) 或 \(x-1,x\)。我们最终希望整个串的最小前缀和非负。
在已有的序列上继续插入需要动态维护 \(0\) 的数量来避免在 \(0\) 后面插入 )(,这就是个无底洞所以我们无法正着做。不妨考虑倒着做,不妨设 \(f_{i,x}\) 表示当前只有单独的一个前缀和为 \(x\),把它扩展 \(i\) 步可以得到的合法串数量。
我们考虑 \(f_i\to f_{i+1}\),只需考虑第一步如何展开即可。显然拆出来三部分在之后的插入过程中独立,组合数乘在一起即可。
直接暴力转移是 \(\mathcal O(n^4)\) 的,无法通过。考虑组合数是一个多重集排列数,可以直接拆开到每个值上,于是我们本质上是想算三个东西的乘法卷积。我们不妨考虑先合并两块一样的,设 \(g_{i,j}\) 表示 \(x=j\),和为 \(i\) 的 dp 值产生的系数,那么转移时我们只需单独乘 \(f_{j,x+1}\) 和 \(f_{j,x-1}\),另外两个用 \(g\) 打包算好。
可以把阶乘吸收到状态里面减小常数。
P12448 [COTS 2025] 观草 / Trava
做了两次都无法战胜,套路叠叠乐还是很厉害。好难啊。
首先 \(i=\sum 1\),我们转化到 \(\sum\limits_{t\ge 1}\sum\limits_{i=1}^{n-k+1}[\max\limits_{i\le p\le i+k-1}\{a_p\}\ge t]\)。可以发现这样的好处是,如果我们可以对每个 \(t\) 单独计数,那么修改就真的变成了单点修改,而不是取 \(\max\) 等麻烦的东西。
然而我们发现这个不好独立做。一个区间做贡献只要存在一个 \(a_p\ge t\) 就可以了,我们不太方便把它摊到 \(t\) 上计数并支持维护。
那么不妨补集转化一下,可以把存在一个转化到全部满足。我们可以转化到:
现在一个区间被数到需要所有 \(a_p<t\) 了。考虑对每个 \(t\) 我们记 \(b_{t,p}=[a_p\ge t]\),那么我们数到一个区间需要要求 \(b_t\) 在一个区间内必须都为 \(0\)。于是不妨记所有的极长 \(0\) 连续段长度为 \(\{len\}\),那么我们查询只需求 \(\sum \max(0,len-k+1)\),把所有 \(len\) 扔到树状数组中就可以简单地求解。
然后考虑单点 \(+1\)。显然这只会导致某个 \(b_t\) 上产生单点修改(\(0\) 变 \(1\)),对 \(len\) 的影响是 \(\mathcal O(1)\) 的,可以用线段树上二分找出左右的 \(1\),然后快速计算。
最后我们考虑怎么初始化。考虑一对 \((i,j)\) 成为相邻的 \(1\) 多少次,可以发现这个值为 \(\min(a_i,a_j)-\max\limits_{i<p<j}\{a_p\}\),我们要对 \(j-i-1\) 贡献这个值的数量。
我们考虑向右扫描 \(j\)。合法的 \(i\) 满足当且仅当 \((i,j)\) 之间的所有数都在它们之下,考虑动态维护还可能有用的 \(i\) 的集合,那么可以发现一个 \(i\) 确认之后没用了当且仅当扫到了一个 \(j\) 使得 \(a_j\ge a_i\),我们知道这其实就是单调栈。据此我们可以发现和每个 \(j\) 产生贡献的 \(i\) 就是当前这一轮单调栈中弹掉的元素,以及最终栈顶的元素。这样就可以完成初始化了。
P12423 【MX-X12-T6】「ALFR Round 5」Coloring Nodes
先考虑思路,我们拿一个树形 dp 算 \(L_i,R_i\) 表示 \(i\) 子树内部的叶子区间,\(f_i\) 表示这些叶子被覆盖完全的最小权值。这个树形 dp 显然是支持换根的,所以我们直接启动换根,把询问离线挂在 \(u\) 上。
这样每个点为根时就会有若干区间及其权值 \((L_i,R_i,f_i)\),我们需要取一些区间覆盖 \([l,r]\),最小化 \(\sum f_i\)。显然这些选出的区间必然是极大的,因为树上的区间只有不交或包含,而我们不会选两个包含关系的区间,也不会选能够被大区间平替的一些小区间,因为大区间的决策在 dp 当中覆盖了这种情况。
形式化地,将所有 \(l\le L_i\le R_i\le r\) 的这些点设置为可选点,我们会选择“最顶层的”那个可选点反链。换句话说,我们选出的这些加入答案的点的充要条件是其可选且其父亲不可选。
考虑到可选的点在树里是一个一个的子树,所以不可选的点是一个以 \(u\) 为根的树,我们想得到这棵树里所有“叶子”节点的儿子的权值和。考虑一个技巧,不妨取 \(f'_i=f_i-\sum\limits_{x\in\text{sons}(i)} f_j\),那么我们把所有不可选的点的 \(f'\) 求和来抵消掉不可选的点的贡献,再用 \(f_u\) 减掉就能得到答案。
于是 \(u=1\) 只需对每一个询问都做一个二维偏序求出 \(f'\) 之和即可。
考虑换根过程,每次换根影响 \(\mathcal O(1)\) 个 \(L,R,f,f'\),我们重新考虑这 \(\mathcal O(1)\) 个点对问题产生的影响,每个点上依旧是个二维偏序。显然我们不好做动态带修二维偏序,我们离线下来三维偏序即可。


浙公网安备 33010602011771号