Cry_For_theMoon  

已经九月了......

1. Sliding Window Sort

拜谢阿兰赵大神。

首先考虑这个过程和 UNR D2T1 其实还挺像的:当执行 \(n-m+1\) 次操作后,最大的 \(m-1\) 个人一定会按大小顺序排在最后。所以我们先来考虑 \(k=n-m+1\) 的,然后容易发现 \(k\lt n-m+1\) 也能套用这个方法解决(我们不关注未被影响到的后缀)。

\(b\) 序列倒推 \(a\) 序列:\(b_0\) 一定是 \(a[0,m)\) 中的最小值,如果 \(b_1\lt b_0\),则它只能放在 \(a_m\),否则 \([0,m]\) 中去掉 \(b_0\) 的位置,剩下的位置它都能任意放置。如果 \(b_1\lt b_0\) 的基础上,\(b_2\lt b_0\) 也成立,那么 \(b_2\) 只能放在 \(a_{m+1}\)

因此可以推出 \(b\) 的每个前缀最大值(除去最后 \(m-1\) 个)有 \(m\) 的贡献,其它位置有 \(1\) 的贡献。

这样我们解决了 \(k\le n-m+1\) 的情况,由于 \(k\) 很大,猜测有一定规律性存在。

手动模拟一下就会发现最后 \(m-1\) 个一定是形成一个整体在动,而且前面 \(n-m+1\) 个人的相对顺序不变,相当于围成了一个环,然后最大的 \(m-1\) 个人位于环上的一个空,每次操作一次,这 \(m-1\) 个人就集体移动到下一个空。

这样我们知道了这个环的形态,但我们还不知道最后的开头是谁。

继续手玩会发现 \(k=n-m+1\) 的时候假设序列开头是位置 \(0\),那么再操作一次开头变成了位置 \(n-m+1\),然后继续操作一段时间好像开头没有变,直到又操作了 \(n-m+1\) 次。所以是之后:每操作 \(n-m+1\) 次后,序列开头减小 \(m-1\)(下标模 \(n\) 意义下)。

我们逆向做这个过程,就能得到这个序列在 \(k=n-m+1\) 的时候的形态,然后就做完了。

时间复杂度 \(O(n)\)

记录

2. Four Suits

拜谢 zhk 大神。

首先考虑枚举一个人 \(i\) 算他的答案,然后钦定他的第 \(j\) 个属性最大。

则我们会在保证有解的情况下,尽量给他尽可能多的颜色 \(j\):也就是假设他被发了一个颜色 \(k\neq j\),而其他人有颜色 \(j\),则交换这两张牌一定不劣。

而这个值也是很好算的,因为我们可以算出每个人还要发多少张牌 \(r_i\),则第 \(i\) 个人此时会被发到 \(\min\{r_i,b_j\}\) 张牌颜色 \(j\) 的牌。

然后考虑二分答案,现在问题变成要把剩下的牌发完,使得除了第 \(i\) 个人以外,其他人的每种颜色的牌不能超过一个值 \(x\),问能否发完。

由于颜色很少,考虑建出匹配或者网络流模型后,利用 Hall 定理之类的在 \(2^4\) 的复杂度内去 check。

现在左边有四种颜色,\(s\) 向他们的连边,容量就代表这种颜色还要发出去多少。右边有 \(n\) 个人,他们向 \(t\) 的连边,容量就代表他们还要被发多少张牌(第 \(i\) 个人的容量此时是要算的,其他人的容量初始就已经确定)。

然后颜色向人的连边是这样的:第 \(j\) 种颜色向第 \(k\) 个人的连边容量,如果 \(k = i\),则就是 \(\infty\),否则是 \(x-a_{k,j}\),因此我们要保证 \(x\) 不小于所有的 \(a_{k,j}(k\neq i)\),这是容易检查的。然后我们要求的就是这张图的最大流。

考虑这里由于边带容量且不方便拆点,所以 Hall 定理不方便检查。考虑这种二分图匹配,还可以直接求最小割:

我们暴力 \(2^4\) 枚举哪些 \(s\) 到颜色的边被删去。不妨设还有 \(c\) 个颜色没被删,此时考虑右部每个点 \(u\) 的贡献,设所有没被删的颜色的 \(a_u\) 之和是 \(s_u\),则这个点的贡献就是 \(\min\{r_u,cx-s_u\}\)

注意到对于每个 \(mask\) 和每个 \(u\),存在一个分界点 \(lim\),使得 \(x\lt lim\) 的时候,这个 \(\min\) 取后者;\(x\ge lim\) 的时候,这个 \(\min\) 取前者。预处理后,容易 \(O(\log)\) 单次对于一个 \(mask\)\(x\),计算所有 \(u\) 的贡献和。然后我们去掉 \(i\) 的贡献和(因为 \(r_i\) 发生了变化),算上它正确的贡献即可。

这样设有 \(k\) 个颜色,则我们需要在 \(O(n2^k\log)\) 的时间内预处理,使得我们能 \(O(\log)\) 单次计算贡献和;然后对每个人都求答案的时间复杂度就是 \(O(nk2^k\log^2)\) 的,一个 \(\log\) 是二分,另一个 \(\log\) 是每次算贡献和。

记录

3. 递增树列

拜谢 cftm 大神。

可以观察到,lca 一定是从 \(1\) 开始的一条根链。

我们可以直接枚举这条链上的最深点 \(u\),然后把 \(1\rightarrow u\) 的路径拉出来,链上的每个点都挂了若干颗子树。

\(n\) 个点有两个属性:颜色 \(c\) 和类型 \(t\)\(c_u\) 表示它的第一个在链上的祖先是谁;\(t_u\) 表示 \(u\) 属于 \(c_u\) 的哪个儿子(如果 \(c_u=u\),则 \(t_u\) 也等于 \(u\))。

定义颜色 \(c\) 的大小关系等价于深度关系,然后我们开始把所有点按照颜色 \(c\) 排序,相同的归并在一起。且保证 \(t\) 相同的点不相邻。这个条件是充分不必要的:我们可以把一个点的位置提前,放到 \(c\) 更靠前的两个位置中间。

所以我们得到这样一种方式不重不漏的生成所有合法数列:从小到大考虑每个颜色 \(c\),从中选出若干个提前插入前面的空位(每个空位只能插一个数),然后如果颜色 \(c\) 留下了 \(x\) 个,就新增 \(x\) 个空位:第 \(i\) 个颜色为 \(c\) 的点之前就是新增的第 \(i\) 个空位。如果一个空位没有填数,则它两边的点,\(t\) 不能相同。

为了保证 \(lca(p_{n-1},p_n) = u\),我们必须保证最后一个颜色(也就是颜色 \(u\))留下来了至少两个人。

有了这些转化,其实多项式做法已经比较明朗了:考虑设 \(h(u,x)\) 表示考虑了链上 \(1\rightarrow u\) 的点,然后后面共有 \(x\) 个人往前插空,这样的一个方案数。

为了转移 \(h\),对链上的每个点,我们要算出这样一个东西:\(g(u,x,y)\) 表示考虑所有颜色为 \(u\) 的点,且有 \(x\) 个人忽略(忽略是因为他们会被移动到前面),且有 \(y\) 个人会插进来的方案数。预处理 \(g\) 后的,\(h\) 的转移是容易的。

为了计算 \(g\),考虑做这样一个经典的 dp:从小到大考虑每个种类,然后设 \(dp(i,x,y)\) 是考虑完前 \(i\) 个种类,删了 \(x\) 个人,还有 \(y\) 个相邻的 \(t\) 相同的对,这样的一个方案数。转移就直接枚举下一个类删了几个人,然后用了多少个空满足原本相邻两个相同,用了多少个空满足原本相邻两个不同,做个插板就能转移了。

最后注意到我们不需要每次拉出一条链重新计算 \(h\),边 dfs 一遍边算就行了。

时间复杂度不太会算,毛估估了一下应该不超过 \(O(n^6)\),而且有一个 \(n^2\) 我感觉是 \(\sum deg^2\),反正跑的很快!

记录

4. Abandoning Roads

大家都喜欢。

考虑 MST 意味着什么,加入所有 \(a\) 边,然后所有的连通块一定都会出现在 MST 里。

因此一条合法的路径里我们离开了一个连通块就不能再回来(也不能走连通块里的 \(b\) 边)。这个问题不方便最短路,考虑只能 \(2^n\times n\) 的状压。

首先如果一个连通块只有一个点那不需要记录,我们发现如果只有两个点也不需要记录,好像三个点也不需要记录。所以状态数是 \(O(2^\frac{n}{4}\times n)\) 的,然后跑最短路即可,复杂度大概是 \(O(2^{\frac{n}{4}}n^2\log)\) 的,跑的很快。

碰到这种很奇怪的数据范围要比较敏感,可能还是指数。

记录

5. 匹配问题

给 CTT 磕头了。

首先把 \(a,b\) 分别排序,有解的事实告诉我们第 \(i\)\(a\) 一定能和第 \(i\)\(b\) 匹配。

从后往前考虑每个 \(a\),则如果我们让他做贡献,它一定会去选最大的在 \([a_i,a_i+lb]\) 范围内的点 \(b_x\),否则它一定会去选最大的在 \([a_i,a_i+la]\) 范围内的点 \(b_y\)。这个是很显然的,问题是我们如何决策?

有结论:只要我们选了 \(b_x\) 后,剩余的 \(a,b\) 能形成完美匹配,我们就会选 \(b_x\);否则我们只能选择 \(b_y\)

使用反证。考虑从后往前第一个不符合的位置:最优解里当前的 \(a_i\) 选择了 \(y\)\(a_j(j\lt i)\) 选择了 \(x\),如果我们能互换 \(i,j\) 的匹配(也就是如果 \(a_j\) 能和 \(b_y\) 匹配),那么我们直接互换。否则一定存在一个点 \(k\)\((j,i)\) 之间,且它此时的匹配点 \(z\)\((x,y)\) 之间,且这个匹配点 \(z\)\(k\) 是无贡献的,且 \(a_z\) 能和 \(b_y\) 匹配,然后我们直接交换 \(i,k\) 的匹配点。重复这个过程直到我们能让 \(i\)\(y\) 匹配上!

理性说明一下:首先 \(a_z\) 能和 \(b_y\) 匹配是基于”如果我们匹配 \((a_i,b_x)\) 则剩余的点对还能形成完美匹配“得到的;匹配点 \(z\)\((x,y)\) 之间是因为假设 \(k\) 连了一个 \(\lt x\) 的位置,则不妨交换 \(j,k\) 的匹配点,由于 \(k\) 这里一定会产生贡献,而且 \(j\) 的匹配点离 \(a_j\) 更近了,所以一定不劣;\(a_z\)\(b_k\) 无贡献是因为 \(k\)\(i\) 之前,而 \(z\)\(x\) 之后。


总而言之,我们已经得到了一个非常简单的 \(n^2\) 策略:每次暴力检查剩余的点能否构成完美匹配,则只需要把 \(a,b\) 分别排序,然后检查第 \(i\) 小的 \(a,b\) 是否能匹配即可。

考虑用数据结构加速检查的过程:注意到我们剩下的 \(a\) 一定是一段前缀(因为我们是从后往前删的 \(a\)),而 \(b\) 却可能删除一些中间位置的点。 因此考虑对每个 \(b_i\) 维护它和哪个 \(a\) 匹配,记作 \(f\)。初始 \(f_i=i\),当我们删除一个点 \(u\) 的时候,会把还存在的,所有 \(u\) 之后的 \(f_i\) 减一。我们只需要快速检查所有的 \(b_i\) 能否和 \(a_{f_i}\) 匹配:注意到这有单调性,如果 \(b_i\) 无法和 \(a_x\) 匹配,自然也无法和 \(a_{x-1}\) 匹配。所以令 \(g_i\) 是最小的 \(j\) 使得 \(b_i\) 能和 \(a_j\) 匹配,我们要检查的就是全局是否满足 \(f_i \ge g_i\)。维护 \(f_i-g_i\) 即可,这样只需要实现后缀加减以及全局最小值,容易用线段树维护。

时间复杂度 \(O(n\log n)\)

记录

6. Nephren Runs a Cinema

好题,就是有点多合一的感觉。

先对答案落在 \(\le R\) 的计数,这个表述形式容易让人联想到卡特兰数,尝试类似转成格路计数,然后套反射容斥。

注意到这个题目里还有一个 VIP,我们考虑对 \(0\sim n\) 的每个 \(i\) 算出 \(f(i)\),表示有 \(i\) 个非 VIP 的人,然后答案落在 \(\le R\) 的方案数;这样 \(\sum f(i)\dbinom{n}{i}\) 就是所求答案。

考虑 \(f(i)\) 的计算:我们先转成格路计数:从 \((0,0)\) 走到一个 \((x,y)\),满足 \(x+y=n\),且 \(x\ge y\)。每次可以向右 / 向上走一个,且不能越过 \(y=x\) 这条对角线; 然后 \(x-y\) 就是剩下的数量。这样的方案数,根据反射容斥可得为 \(\dbinom{i}{x} - \dbinom{i}{x+1}\)。那么合法的 \(x\) 取值范围是什么?将不等式 \(x\ge (y=n-x)\) 以及 \(x-(y=n-x)\le R\) 联立可以解除 \(x\) 的取值范围 \([L,R]\),然后我们只需要算 \(\dbinom{i}{L} - \dbinom{i}{R+1}\)

这样我们就能在 \(O(n)\) 时间内算出答案,压力来到任意模数上:此时我们无法求组合数。

任意模数下的乘除法有这样一个东西在:只要我们能保证运算结果封闭在整数域,就能做除法(但注意无法做加减法)。

将模数分解质因数 \(p_1,p_2,...,p_k\),然后任何一个非负整数都能唯一写成 \(p_1^{a_1}\times ...\times p_{k}^{a_k}\times r\) 的形式,其中 \(r\) 是一个和模数互质的余项。

这样的形式下,做乘除法是很容易的:对于 \(a_i\) 这些指数项直接做加减法;对于两个 \(r\) 的乘除法,由于 \(r\) 始终与模数互质,因此可以用 exgcd 求出它的逆元。这样做一次除法的复杂度是 \(O(\log)\) 的,和素数模数一致。但是求值的时候由于我们要用快速幂计算每个 \(p_i^{a_i}\),所以应当会慢一些,在 \(O(\log^2)\) 左右,当然实际上效率还是不错的。

然后我们就可以求出 \(0\sim n\) 的阶乘,然后就可以快速求出组合数了。

记录

7. New Year and Binary Tree Paths

爵士好题。

先来考虑祖先 - 后代链如何计算。

假设顶端节点的值是 \(x\),我们枚举点数 \(k\),然后 \(x(2^0+...+2^{k-1})\) 这部分贡献是一定存在的。对于第 \(i\ge 2\) 个点,当我们从 \(i-1\rightarrow i\) 的时候,可以自由选择在这一位补 \(0\) 还是 \(1\);如果补 \(1\),则它在第 \(i\) 个点贡献 \(2^0\),在第 \(i+1\) 个点贡献 \(2^1\),依次类推,它的总贡献是 \(2^{k-i+1}-1\)

因此实际上是这样一个事情:令 \(r = s - x(2^k-1)\),然后对于每个 \(1\le i\le k-1\),我们都能令 \(r\) 减去 \(2^i-1\),然后要求令 \(r=0\) 的方案数。

注意到很关键的一点是:\(\sum_{i=1}^{k-1}(2^{i}-1)\) 是一定小于 \(2^k-1\) 的,所以我们只能令 \(x\)\(\lfloor \frac{s}{2^k-1} \rfloor\)。因此 \(r\) 固定为 \(s\bmod (2^k-1)\)。注意到此时方案数 \(\le 1\):我们从高位往低位开始不断检查是否要减去 \(2^i-1\) 即可。这样我们就处理完了祖先 - 后代链。

联想到两条链的情况应该也是类似的:假设路径顶点位于 \(x\),然后 \(x\) 的左右儿子必选,枚举左右链的点数(包含 \(x\))分别为 \(dl,dr\ge 2\)。然后 \(x\) 本身的贡献是 \(x(2^{dl}+2^{dr}-3)\)。对于左链:必选 \(2^{dl-1}-1\),对于右链,必不选 \(2^{dr-1}-1\),然后左边对于 \(i\le dl-1\)\(2^{i}-1\) 可以自由决定选不选;右边同理。(可以注意到我这里其实左右链搞反了,在我这里左链是 \(\times 2+1\) 的,不过也无所谓。)

类似地:\(\sum_{i=1}^{dl-1}(2^{i}-1) + \sum_{i=1}^{dr-2}(2^i-1)\) 一定小于 \(2^{dl}+2^{dr}-3\)。因此 \(x\) 依旧唯一,因此 \(r\) 唯一取到 \(s\bmod (2^{dl}+2^{dr}-3)\)。然后考虑数位 dp:直接设 \(dp(i,j,k)\) 表示考虑完了 \(r\) 的末 \(i\) 位,还有 \(j\)\(1\) 在更高位会终止,当前进位为 \(k\) 的方案数;转移直接枚举下一位,左链右链分别选 \(0\) 还是 \(1\)。时间复杂度 \(O(\log^5 s)\)

记录

8. K Paths

好题。

考虑枚举 \(k\) 条路径的交 \((u,v)\),然后考虑 \(u\) 从一侧的每个子树里选择若干个端点(不能有两个位于相同分支),然后剩下的全部选择 \(u\)\(v\) 同理。假设 \(u\) 这里有 \(i\) 个没有选择 \(u\) 本身,那对答案的贡献就是 \(\frac{k!}{(k-i)!}\)。因此如果 \(u,v\) 不是互为祖先关系,可以对 \(u,v\) 的儿子分别做分治 NTT 得到 \(F(u) = \sum f_u(i)\frac{k!}{(k-i)!}\),然后 \(F(u)\times F(v)\) 就是这对\((u,v)\) 的贡献。

问题在于 \(u\)\(v\) 的祖先这种情况,设 \(v\)\(u\)\(w\) 子树里的,则 \(f_u(i)\) 那里的计算要除掉多项式 \((1+sz_w x)\),这个很棘手。

\(u\) 的视角来看,我们不在意 \(v\) 而只在意 \(w\)。因此对子树 \(F\) 求和,然后我们只关心 \(F(w)\)

也就是求:\(\sum_{w\in son(u)}F(w)\times \prod_{v\neq w}(1+sz_v x)\times (1+(n-sz_u)x)\)

这个东西也可以分治 NTT 求出:只用额外维护区间的 \((1+szx)\) 的乘积即可。

时间复杂度 \(O(n\log^2 n)\)

记录

9. 校园旅行

很神的 idea。

考虑我们实质上需要对所有的 \((u,v)\) 都求出他们之间的答案。因此考虑类似 bfs 地不断拓展:假设我们知道了一对 \((u,v)\) 合法,则所有满足:\((u,x),(v,y)\in E\)\(a_x=a_y\)\((x,y)\) 也会合法。我们加入辅助状态 \(f(u,v)\)

\((u,v)\) 拓展的时候向所有 \(f(u',v)\) 连边(保证 \(u',u\) 有连边),然后 \(f(u',v)\) 再向所有 \(f(u',v')\) 连边(保证 \(v',v\) 有连边且 \(a_{u'}=a_{v'}\)),然后跑 bfs。这样我们得到一个 \(O(nm)\) 的解法,可以获得\(70\) 分。

考虑也无法很好地快速找到剩余的有效点对,因此很难在 bfs 的部分进行优化。然而本题的边数可以减少:我们考虑回文串可以拆分成三部分:若干个 \(0\),若干个 \(1\),还有 \(01010101...\)

考虑所有连接两个 \(0\) 的边,取出他们。然后考虑一个连通块,如果我们只走这些边,然后从 \(s\) 走入 \(t\) 走出;则我们其实只关心这条路径的奇偶性(因为能走非简单路径,因此路径总是能走足够长);如果是二分图,则图上任意两点距离奇偶性确定,我们直接保留一颗生成树即可;否则,我们在生成树的基础上随机添加一个自环,就能支持奇偶性的改变(当然也可以随机一个奇数距离的两点,然后加入一条非树边)。

对于 \(11\)\(01\) 同理,然后每种情况最多带来 \(O(n)\) 的连边,因此我们可以把这张图的边数降到 \(O(n)\) 而不改变答案,时间复杂度 \(O(n^2+m+q)\)

记录

10. 六元环

攻击了我很久的困难题,终于解决!(其实是 hb 模拟和 nfls 模拟都出了。。)

首先考虑没有修改操作,如何快速统计答案。

建出 \(a_1,a_2,...,a_n\) 的大根笛卡尔树(值相同的时候认为左边大),则答案等价于笛卡尔树上的大小为 \(4\) 的连通块个数(但不包含根)。

这样我们可以 \(O(n)\) 处理一次询问:直接建出笛卡尔树然后 dp 即可。但这样没有利用到 \(a_x\) 单调增的性质。

考虑维护笛卡尔树的变化:当 \(a_x\) 增加的时候,这个点会不断上旋至某一处,然后停止(这里的上旋定义和平衡树一致)。

观察部分分,猜测到总的上旋次数不会太多,我们暴力上旋,每次旋转完对 \(O(1)\) 个点重新计算它们的 dp 值,这样其实已经可以获得 \(80\) 分。

可以通过类似 LCT 的分析方式得出:我们在上旋过程中,变向(指从左旋变成右旋,或者反之)的总次数是 \(O(n\log n)\) 的。

而当我们的 \(x\) 在一条很长的左链上,我们把他左旋到链顶时,手玩发现其实也只有 \(x\) 附近,还有链顶 \(O(1)\) 个位置的树结构发生变化,需要重新 pushup。

现在问题变成:如何每次找到链顶,以及当我们无法旋转到链顶时,究竟要旋转到哪个位置?

这个问题难以在树上维护,因为笛卡尔树的形态一直在发生变化。但注意到整个中序遍历 \(a_1,a_2,...,a_n\) 是不变的,且笛卡尔树和序列可以紧密结合。事实上如果我们想找点 \(x\) 是它父亲的左儿子还是右儿子,只需要:

  • 找到左边第一个大于等于 \(x\) 的位置 \(L\),以及右边第一个大于 \(y\) 的位置 \(R\)。(认为 \(a_0=a_{n+1}=\infty\))。
  • 如果 \(a_L \ge a_R\),则说明 \(x\) 是父亲的右儿子;否则说明 \(x\) 是父亲的左儿子。

假设 \(x\) 是父亲的右儿子,则我们就要找到一直向上跳,直到链顶。这个链顶这样找:向右找到第一个大于 \(a_L\) 的位置 \(p\),然后 \((x,p)\) 内的最大值位置(如果有多个算最靠左的)就是链顶。

我们解决了第一个问题;第二个问题,如果这个链顶 \(v\) 不能被 \(x\) 上旋换掉,该如何找链 \(x\rightarrow v\) 上最后一个能旋到的位置?依旧线段树二分找到 \((x,v)\) 中第一个大于 \(a_x\) 的位置,然后这个位置的左儿子就是最后一个能旋到的位置(需要特判这个儿子是 \(x\) 本身的情况)。

这样时间复杂度 \(O(n\log^2 n)\),需要注意常数。

11. Ciel and Flipboard

好题!

感觉这个问题非常不可做,突破点是 \(m=\frac{n+1}{2}\),所以最中间这一行这一列比较重要。

会发现一个事情:任何一个操作都会经过第 \(m\) 行和第 \(m\) 列。

现在考虑只有一行,且以 \(m\) 为中心:对于任何一个 \(x\lt m\),我们发现第 \(x\) 个点和第 \(x+m\) 个点,二者一定恰好有其一被翻转,且 \(m\) 一定被翻转。

由此,设 \(f(x)\) 表示位置 \(x\) 是否被翻转了,则 \(f(x)\oplus f(m)\oplus f(x+m)\) 一定为 \(0\)

对于列,我们也能做出这样的事情。因此如果我们确定了前 \(m\times m\) 个格子是否被翻转,一定能确定剩下的所有格子是否也能被翻转。所以答案的可能性不超过 \(2^{m^2}\),另一方面,可以发现所有可能的操作是线性无关的,所以答案数就应该是 \(2^{m^2}\),所以任何一种前 \(m\times m\) 个格子的填法都是合法的,也对应了所有的可能操作方式。


我们直接枚举:第 \(m\) 行的前 \(m\) 个格子,还有第 \(m\) 列的前 \(m\) 个格子;这 \(2m-1\) 个格子确定后,整个第 \(m\) 行第 \(m\) 列也被确定,且对于任何一个 \(x,y\lt m\),我们确定了 \((x,y)\) 就随之确定了 \((x+m,y),(x,y+m),(x+m,y+m)\),而且不同的 \((x,y)\) 相互完全独立。这样我们就可以直接看这四个位置是 \((x,y)\) 翻转还是不翻转更优秀即可。这样我们得到一个 \(4^mn^2\) 的做法。

如何更进一步?考虑得到一个 \(2^m\) 级别的算法:我们来尝试只枚举第 \(m\) 列的前 \(m\) 个格子,然后我们发现,我们对每个 \((m,i)\)(其中 \(i\lt m\)),暴力枚举它是 \(0\) 还是 \(1\),然后 \((m,i+m)\) 被确定,然后所有 \((j,i)\)(其中 \(j\lt m\))对应的那四个格子的最优解也能算出来。因此我们直接得到了一个 \(2^mn^2\) 的做法!

记录

12. Deja Vu

我的评价是,这个题,难度评低了。

首先我们随机手玩一些路径:发现如果有一个时刻,边的序列比点的序列长,那么我们其实就强制了未来几步点的走法,如果能走,那么最后一定会有一个时刻两个序列相等(或者由于长度太大直接寄)。

问题在于:如果点的序列比边长,就假设长 \(1\),如果下一步是非空边,那好办,但题目里有空边,我们没法处理我们走很多步空边的情况。

此时一个很高妙的想法出现了:我们规避,头疼这种情况,就把他记录进状态里:\(f(i,u,0/1)\) 表示我们的路径长度为 \(i\),落在点 \(u\);若为 \(0\),则表示边的序列长度为 \(i\),否则代表长度为 \(i-1\)

也就是我们避免不了这种情况,但是强制这种情况下点序列只比边序列长 \(1\),这是可以做到的。

然后来思考转移。

  • \(0\rightarrow 0\):拼接上一个缺开头的路径。
  • \(0\rightarrow 1\):拼接上一个既缺开头,又缺结尾的路径
  • \(1\rightarrow 0\):拼接上一个合法路径。
  • \(1\rightarrow 1\):拼接上一个缺结尾的路径。

问题是,我们的转移系数如何设置?几乎在写出这些转移的瞬间,我们就意识到会算重。

我们考虑预处理出 \(g(len,i,j,0/1/2/3)\),表示极短的,长度为 \(len\),起点为 \(i\) 终点为 \(j\) 的路径。最后一维分别代表属于上面的哪种情况。

如何处理 \(g\)

首先先来考虑 \(g(2)\),也就是合法路径。

注意到一个性质:合法路径上一定存在一条边 \((x,y)\),使得这条边上也包含 \((x,y)\) 这个点对。直接枚举它然后暴力向两侧拓展就能找到一个极小的 \(g(2)\)

再来考虑 \(g(3)\):考虑最后一条边,如果它是空的,那就是一个 \(g(2)\) 拼了一个空边,这样是无意义的。否则最后一条边 \((u,v)\) 的结尾一定是 \(u\),然后考虑还是不断向前暴力拓展,这样所有极小的 \(g(3)\) 也能被找到。

再来考虑 \(g(0)\):考虑第一条边 \((u,v)\) 的开头,这条边不能是空的,否则这条缺开头的路径可以被拆分成空边 + 一条合法路径;因此这条边的开头一定是 \(v\),然后不断向后暴力拓展,这样 \(g(0)\) 也算完了。

最后考虑 \(g(1)\),它一定是空边。

然后 \(f\) 的转移反而很简单:直接 \(f + g\rightarrow f\) 合并就行了。时间复杂度 \(O(n^4)\),预处理也是这个复杂度。

记录

13. Hardcore String Counting

比较套路的题?

首先意识到这大概率是一个多项式题目,然后 \(m\) 很大,考虑应该是求 \([x^m]\frac{P(x)}{Q(x)}\) 这种东西。

考虑容斥,我们钦定一些位置出现了 \(S\)(钦定的位置是结尾),那么考虑会构成若干个连续段。不同连续段里还会有若干个可以任选的字符插空。设连续段的生成函数为 \(F(x)\),插空的生成函数是 \(G(x)\),令 \(H(x) = G(x)F(x)\),很显然所求的就是 \([x^m]\frac{1}{1-H(x)}\)

然后令 \(f(x)\) 是一个 \(n\) 次多项式,当且仅当 \(i\)\(S\) 的周期(且 \(i\lt n\))的时候 \(x^i\)\((-1)\)(且非 \(0\))。

\(F(x) = -x^n(1+f(x)+f^2(x)+...) = \frac{-x^n}{1-f(x)}\)

\(G(x)=\sum_{i\ge 0}c^ix^i=\frac{1}{1-cx}\),其中 \(c=26\)

\(H(x) = G(x)\times F(x)\),则答案就是 \([x^m]\sum_{i\ge 0}H^i(x) = [x^m]\frac{1}{1-H(x)}\)

展开 \(H(x)\)\(\frac{-x^n}{(1-f(x))(1-cx)}\),不妨记作 \(\frac{P(x)}{Q(x)}\),则所求就是 \([x^m]\frac{1}{1-\frac{P(x)}{Q(x)}}=[x^m]\frac{Q(x)}{Q(x)-P(x)}\),然后套用 bostan-mori 算法即可在 \(O(n\log m\log n)\) 的时间内解决。

记录

14. 最小连通块

非常有趣的交互题!

首先考虑设计一个能拿分的算法:我们可以花费 \(1\) 次操作询问 \(x\) 是否是 \(y\) 的祖先(以 \(1\) 为根的时候)。然后共 \(n^2\) 次求出一个拓扑关系,按照这个拓扑关系就能自顶往下还原整棵树,应该能获得 \(2\) 分。

考虑求树形态的一个常见算法是剥叶子:我们可以 \(1\) 次操作询问 \(u\) 是不是叶子,只需要看 \(u\) 是否在全集 \(V\) 去掉 \(u\) 的最小连通块内即可。这样我们每次暴力找到一个叶子,那么第 \(i\) 轮最多询问 \(n-i\) 次,这样期望能得 \(4\) 分。

注意到上述询问方式使用的都是非常特殊的情况,比如 \(|S|=1\) 或者 \(|S|=n-1\) 之类的;我们尝试用一些操作组合出一些基本操作,然后用这些基本操作来降低询问次数。这也是交互题比较常见的手法。

我们从 \(1\) 开始,每次可以 \(O(\log)\) 次询问内(利用二分)找到一个点 \(u\),满足 \(u\)\(1\) 的后代;我们重复这个过程直到找到叶子。这样期望 \(O(\log n)\) 次跳跃找到一个叶子( 如果我们每次随机打乱点集顺序)。那么就在期望 \(O(n\log^2 n)\) 的次数内还原了树,分数一下子就上来了。

突然发现一个问题:我们可以每次删掉一个叶子,但是如何确定这个叶子和谁连边?

我们倒着确定拓扑序(也就是剥叶子),然后遍历这个拓扑序(也就是自底至顶遍历):当我们当前节点是 \(u\) 的时候,我们直接找到 \(u\) 的所有后继,然后把这些后继从全集里删除(以后找后继的时候初始就忽略它,注意不删除 \(u\))。则我们每次找到的后继应该就是 \(u\) 的儿子。这里的总次数是 \(n(\log n+1)\) 的,因为每个点在找不到后继退出的时候会浪费一次操作,然后每个点会被父亲问一次。这里 \(\log n\) 应该是上取整,也就是 \(10\)

所以我们的 \(O(n\log^2 n)\) 做法就没有假。现在考虑用这个基本操作(找后继)做更多的事情。

我们考虑把 \(u\) 内的所有点加入拓扑序并删除,若 \(u\) 是叶子则很好办,否则我们随便找到一个后代 \(v\),然后递归下去删 \(v\),删完后继续回来在 \(u\) 这里重复执行。则这里的总次数也是 \(n(\log n+1)\) 的,因为每个点找不到后继(说明它是叶子)的时候浪费一次操作,然后每个点还是只会被找到一次。

这样刚好卡到 \(2.2\times 10^4\),当然我们的点集并不总是 \(n=1000\),所以这个 \(\log n\) 并不会满,可以轻松通过。

15. Prime Flip

很神的题!

首先考虑差分,令 \(f_i = a_i \oplus a_{i-1}\),则我们的目标就是让 \(f\) 全变成 \(0\)

我们的操作相当于选定两个距离为奇质数的点,同时翻转他们的状态。

根据哥德巴赫猜想,如果两个点的距离为偶数,我们可以通过两次操作翻转这两个点的状态(如果 \(n=2\),则先转一次 \(3\) 再转一次 \(5\)) ;如果两个点的距离为非质数的奇数,我们一定可以通过三次操作翻转这两个点的状态(先加上任意一个足够大的奇素数然后变成距离偶数的情况)。

那么我们就是相当于找一个一般图最大权匹配,这样至少获得了一个多项式做法。

再从边权的特殊性入手:如果我们确定了哪些点对之间的边权为 \(1\)(距离为奇质数),剩下的点对的匹配是很好分配的:我们会把奇偶相同的优先匹配,代价为 \(2\),最后剩下最多一对奇偶不同的,代价为 \(3\)

然后此时可以发现,我们选一对距离奇质数的匹配,相当于从奇数和偶数那里同时拿走了一个。此时代价一定不会变大(可能匹配后,会出现让奇偶这里额外剩下一个,从而多出一对 \(3\) 的匹配,但是两边都少了一个 \(2\) 的匹配,因此代价的变化是 \(+3+1-2-2\))。

所以我们只需要求出奇质数距离的最大匹配即可,这里直接跑二分图最大匹配,用网络流就可以做到 \(O(k^{2.5})\)

记录

16. Game On Tree

比较常规的数据结构。

先来思考 \(A\) 的策略:一定是走到一个点然后摆烂不动。

证明基于这样:如果我们第一次走了一个以前经过的点,因为是树,所以这个节点一定是上一次才走过的,也就是直接 \(u\rightarrow v\rightarrow u\) 这样;可以发现这样还不如直接在 \((u,u)\) 这里直接摆烂:对于 \(u\) 这一侧的 \(B\),以及 \(v\) 这一侧的 \(B\),最后的距离都没有变化。

然后来考虑定根的情况:设 \(f_u\) 是最近的 \(B\)\(u\) 的距离,则我们能从根走到 \(u\) 当且仅当对于路径上的每个点 \(x\)(不包含 \(u\)),都有 \(dep_x \lt f_x\),也就是我们走到点 \(x\) 的时候,还没有人来得及拦住 \(A\)

注意到如果有 \(x\)\(y\) 的祖先,且 \(dep_x \ge f_x\),那一定也有 \(dep_y\ge f_y\)。因此我们要检查能否走到 \(u\),只需要检查 \(u\) 的父亲 \(w\) 是否满足 \(dep_w\lt f_w\)。然后我们得到一个 \(O(n^2)\) 的做法。

考虑换根:假设初始以 \(1\) 为根,最后换根到 \(u\),则考虑若 \(v\) 不在 \(1\rightarrow u\) 上,以 \(u\) 定根时,它的父亲没有变化;否则以 \(u\) 定根时,它的父亲是 \(1\rightarrow u\) 这条链上的后继。

我们先不考虑后一部分:由于能在 \(u\) 摆烂当且仅当 \(u\) 的父亲不会被拦截(以 \(1\) 定根时),所以令 \(g_u\) 是每个点儿子的最大的 \(f\)。然后当且仅当 \(f_u\lt dep_u\) 的时候,\(g_u\) 会被贡献到当前根节点的答案。

注意到 \(dep_u\) 也就是 \(u\rightarrow rt\) 的距离,也就是每个点对一定距离以内的点做贡献。这可以建出点分树以后在 \(O(n\log n)\) 的时间内做到(注意到本题的树是无边权的)。

现在考虑 \(v\)\(1\rightarrow u\) 链上的情况:此时我们不要求走到 \(fa_v\),只要能走到 \(v\) 的那个儿子就够了。可以倍增出最浅的向上走能走到的点,然后求的就是这一段里的 \(\max f\),同样在 \(O(n\log n)\) 的时间内解决。

(没有意识到边权为 \(1\) 的特殊性质,所以点分那里带二分,写丑了。)

17. Boring Card Game

非常高质量的构造。

这个每次拿三张牌很怪:先考虑每次拿两张牌的情况。

我们拿了中间的两张牌,旁边的就连续了,它长得非常像括号匹配。我们给每张牌染上颜色表示它是谁染色的,然后把颜色看成两种括号,用栈做括号匹配,因为一定有解,所以总能做出括号匹配。

然后建出括号树,应该是有若干棵树的,且满足:父亲节点的括号对颜色一定和儿子节点的括号对颜色不同。

且一个点只有在作为叶子的时候才能被删。我们将说明总有合法的删掉所有节点的方式,所以我们强行加了一个括号树的限制,然后发现在这样一个强制约束下原问题依旧总能有解,这样加强约束的手法非常高妙。

如果是先手:一定存在一个属于他的叶子。假设没有,则每个属于先手的节点都不是叶子,将他们与属于后手的儿子匹配,因为此时先后手节点相等,所以每个后手的点都会有父亲(因此每个先手的节点恰好只有一个儿子)。但是由于后手最后一步操作,一定有一个节点的根是属于后手的,这就矛盾了。

如果是后手:可以类似证明,一定存在一个属于后手的可删的点:但是需要注意!如果删的点是一个孤立点(也就是树根),且其它的树根都不属于后手,且当前不是最后一轮操作,那我们不能删去这个点);但可以发现此时一定还存在另外一个可以删的点。因此我们建出括号树后一定有解。

回归每次拿三张牌的情况,我们还是一样的手法做括号匹配:当栈顶三个数的颜色相同就弹出,并且以最左边的作为左括号,最右边的作为右括号。本质没有任何区别。

直接暴力模拟上述过程就能做到 \(O(n^2)\),稍微注意实现其实也可以做到 \(O(n)\)

记录

18. Gregor and the Two Painters

很有 cf 风格的 Data Structure!

考虑直接算连通块数量很困难,因此为每个连通块钦定一个 \(a_i+b_j\) 最小的位置作为代表,如果有多个则取横坐标最小的,还有多个就取纵坐标最小的。

这样就变成了有多少个 \((i,j)\) 满足 \(a_i + b_j\le X\) 且它不能走到一个比他优秀的点。

\(L_j\)\(b_j\) 左侧第一个 \(\le b_j\) 的位置,则 \((r,j)\) 合法必须满足无法走到 \((r,L_j)\),也就等价于这之间有一个人满足 \(a_r + b_k \gt x\)。对右侧同理。

\(a\) 来说也同理。

我们预处理 \(c_y\) 表示当取在第 \(y\) 列的时候,\(a_r\) 至少要多大才能满足 \(L,R\) 都走不到;类似定义 \(d_x\)。为了 \(a_i + b_j \le X\),我们再给 \(c_y\) 设置一个上界 \(e_x\)。现在只需要对符合以下条件的 \((x,y)\) 计数,满足:

  • \(a_x \ge c_y\)
  • \(d_x\le b_y \le e_x\)

按照 \(a_x\) 从小到大加入考虑每一行,则如果一个 \(y\) 先前满足 \(a_x\ge c_y\),现在也一定合法。

对于第二个条件,我们把满足第一个条件的 \(y\) 放在 \(b_y\) 位置,然后就变成了查询 \([d_x,e_x]\) 的区间和。

时间复杂度 \(O((n+m)\log n)\)

记录

19. Watching Cowflix

如果能开到 \(10^5\) 就好了,现在有点卡常。

考虑确定 \(k\) 怎么做:可以设 \(f(u,0/1)\) 表示以 \(u\) 为根的子树的答案,第二维表示 \(u\) 是否被选中。这样我们得到一个单次 \(O(n)\) 的解法。

注意到有一个上界是 \(n+k\),因此我们选的个数不会超过 \(\frac{n}{k}+1\)。所以当 \(k\gt \sqrt{n}\) 的时候我们最多选 \(\sqrt{n}\) 个连通块。因此我们对 \(k\le \sqrt{n}\) 的情况暴力 dp;对于 \(k\gt \sqrt n\) 的情况,设 \(f(u,x,0/1)\) 表示 \(u\) 子树内选了 \(x\) 个连通块(不考虑 \(k\) 的贡献),且 \(u\) 是否被选中,此时的一个答案。然后我们就在 \(O(n\sqrt n)\) 的时间内解决了本题。

为了应对空间限制,可以适当把第一部分的阈值开大,但是这样的话就有可能在第一部分超时;我们可以把 dfs 序预先跑出来,按照顺序 dp,这样常数就会小很多,因为我们不需要 dfs 了。

记录

20. Lazy Numbers

首先 \(rk(i)=i\) 是个很神必的东西,这个看上去就无法做数位 dp 状物,不能 dp,太难受了。

猜测 \(rk(i)-i\) 有一些性质,比如单调,但是打个表算一些小的 case 发现并没有。

但是打大一点出来会发现好像当 \(n\) 变大的时候,似乎后面的 \(rk(i)-i\) 基本都是单调的。

思考一下 \(i\rightarrow i+1\) 的时候 \(rk(i)\) 的变化,原则上来说要么末位变大,要么进位,此时上一位变大,好像 \(rk(i+1)\) 总比 \(rk(i)\) 大?那为什么假了。原来是有进位,就是说如果 \(i+1\) 的位数变了,那最开始就会多出一个 \(1\)

所以有结论:假设 \([L,R]\) 内的数,\(k\) 进制下位数是一致的,则这段内 \(rk(i)-i\) 就是单调增的。

那我们就能二分了,现在压力来到算一个数的 \(rk\)

统计多少个数 \(y\) 满足 \(rk(y)\le rk(x)\) 首先算掉 \(y\)\(x\) 的前缀的情况,否则枚举 \(lcp = i-1\),然后枚举位数。当位数 \(\lt len(n)\) 的时候,我们任意填都是可以的,所以不需要真的枚举;当位数 \(=len\) 的时候,我们需要做一些简单的讨论。总之可以 \(O(\log n)\) 算出 \(rk(x)\)

然后整个问题就在 \(O(\log^3 n)\) 的时间内得到了解决。

记录

21. MEXanization

给场切的怪兽磕一个。

首先考虑给定集合的 \(f(S)\) 如何计算?我们猜测答案具有可二分性,但是第一组样例的第一个值给了我们提醒:需要特判 \(|S|=1\) 的情况;然后 \(|S|\ge 2\) 的情况应当具有单调性,且答案随着添加数的增多而变大。

考虑二分答案:现在判定是否能将 \(mex\) 变为 \(x\)

定义 \(f(x)\) 是我们需要多少个 \(x\),假设我们现在有 \(a\)\(x\),那么如果 \(f(x) \gt a\),就需要 \(f(x)-a\)\(0\sim x-1\),否则我们就多出 \(a-f(x)\)\(x\) 可以自由使用。

因此考虑如下过程:维护一个 \(r\),初始 \(r\)\(\ge x\) 的数的个数,这些数我们能够自由支配。然后 \(f(0\sim x-1)\) 全部为 \(1\)。现在倒序从 \(x-1\rightarrow 1\) 考虑,再记 \(b_i\) 是初始有多少个人 \(=i\)。然后如果 \(f_i \gt b_i\),则令 \(f_{0\sim i-1}\) 全部加上 \(f_i - b_i\);否则令 \(r\) 增加 \(b_i - f_i\)。最后只需要检查是否满足 \(f_0 \le b_0 + r\) 即可。

这样我们得到一个 \(O(n^2\log n)\) 的算法:实际上则不需要二分,因为前缀答案的单调性,我们直接双指针即可。这样得到一个 \(O(n^2)\) 的算法(当然需要特判第一个位置)。

继续观察我们的过程,发现一件事情:\(f_i \gt b_i\) 的位置最多存在 \(O(\sqrt n)\) 处,否则一定无解。我们考虑所有这样的位置为 \(r_1,r_2,...,r_k\)。则 \(r_i\) 让前面的所有位置增加 \(f_{r_i}\),那不难发现最开头的 \(f_0\) 就会至少增加 \(1+2+3+...\) 这种东西。

那么如果我们能快速每次找到前面这样的第一个位置就好了,因为中间的那些 \(r:=r+b_i-f_i\) 的操作,由于中间的这段 \(f\) 都是相同的,所以只需要求出 \(b\) 的和即可。由于有 \(O(n)\) 次修改,\(O(n\sqrt n)\) 次询问区间 \(b\) 的和,考虑用分块平衡掉,这部分复杂度为 \(O(n\sqrt n)\)

然后就只剩快速找到前面第一个 \(f_i\gt b_i\) 的位置了:其实发现一个事情,就是我们扫到 \(i\) 的时候,所有 \(j\lt i\)\(f_j\) 其实是一个定值,我们直接维护这个值 \(F\) 即可,那就是找前面第一个 \(b_i\lt F\) 的位置。这个可以直接线段树二分出来。

这样我们就得到了一个 \(O(n\sqrt n\log n)\) 的做法,但是他看着就有点危险,最后也确实过不去。

感觉线段树二分的部分无法去掉了,也无法根号平衡掉。我们考虑这个 \(O(\sqrt n)\) 的界,实际上要卡的满的话,我们的询问点 \(r_1,r_2,...,r_k\) 应当得挨在一起,且比较靠前。所有我们每次向前找位置的时候,先对 \(O(1)\) 个前面的位置暴力检查,如果没有找到,再跑线段树二分,这样常数就小很多,可以通过。

记录

22. 棋盘上的旅行

HDU 的效率。。。

设答案路径上我们依次经过了颜色 \(a_1,a_2,...,a_k\),我们给每种颜色打上 \([0,k)\) 的一种,则有 \(\frac{k!}{k^k}\) 的概率,\(a_1,a_2,...,a_k\) 的颜色互不相同。

然后直接设 \(f(i,j,mask)\) 表示当前位于 \((i,j)\),且走过的点里,出现了 \(0\sim k-1\)\(mask\) 内的数,直接跑 \(bfs\) 即可。

上述过程根据概率分析,期望 \(\frac{k^k}{k!}\) 次就能出解,我把系数设为 \(2.5\) 才能通过。

其实这个套路也能拿来做什么最大的长度为 \(k\) 的简单路径,或者最大的 \(k\) 元环,都是基于最优解有 \(\frac{k!}{k^k}\) 的概率被命中。

23. 度度熊算算术

先考虑链上的情况:我们直接 \(dp(i,j)\) 表示把 \(1\sim i\) 分成 \(j\) 段的答案。但是存不下,考虑取 \(\log\) 后变成 \(\sum\) 最大。

这样是 \(k\) 轮,每轮 \(O(n^2)\) 的,考虑有决策单调性在:因为根据基本不等式我们想让每段的和尽可能接近,所以不会出现 \(i\) 后移,决策点前移的情况。

这样就能做到 \(O(nk\log)\)

现在考虑环上的答案:注意我们随机一个位置断开,有 \(\frac{k}{n}\) 的概率命中答案的。所以我们期望 \(\frac{n}{k}\) 次随机做这个 \(dp\) 就可以。这样复杂度就是 \(O(n^2\log n)\) 了。当然实际计算一下可以发现仅仅取到 \(\frac{k}{n}\) 是不够的,大概取到 \(\frac{7n}{k}\) 左右正确率就接近 \(99\%\) 了。

记录

24. Collecting Balls

填数游戏导致的。。

首先考虑指数级别的做法:当一个点被横向的机器人取走,我们打上 \(L\) 的标签,否则打上 \(U\) 的标签。则有以下限制:

  • 每一行恰有一个 \(L\) 标签。
  • 每一列恰有一个 \(U\) 标签。

我们可以直接枚举哪 \(n\) 个点取 \(L\)。当每个点的 \(L/U\) 确定后,我们该如何计算?

如果一个点是 \(L\),则同行所有在他之前的点必须要被取走;如果一个点是 \(R\),则同列所有在他之前的点要被取走。发现这是一个有向的拓扑关系,拓扑序计数能做的只有树:事实上连边关系也确实构成树,因为每个点只会最多有一个后继。

我们知道树的拓扑序计数是 \(n! \times \prod_{i=1}^n\frac{1}{sz_i}\)。那么我们考虑每个点取 \(L/U\) 的时候 \(sz^{-1}\) 分别是多少,然后根据他是 \(L/U\) 来决定乘上对应的 \(sz^{-1}\),最后额外乘上 \((2n)!\) 即可。这样就有了一个指数级别的做法。

来考虑每个点打 \(L/U\) 标记很有讲究:每一行每一列恰有一个,很像二分图匹配。因此考虑建出行列的二分图,位置 \((i,j)\) 便连边 \((r_i,c_j)\)。此时我们发现其实这就是省选 D2T2 的 trick:此时变成了给每个点分配一条对应的边,如果一条边被分给了左部点那就是 \(L\) 否则就是 \(U\)。且要求所有点都有边分配,那么每个连通块一定都是基环树,否则无解。

对于基环树,分配方式也只有两种,取决于基环。那么对两种情况,我们算出对应的 \(\prod sz^{-1}\) 后相加;每个连通块的答案乘起来即为答案。

时间复杂度 \(O(n) / O(n\log n)\),取决于一些实现。

25. Region Separation

好题!

这个看上去非常不可做,首先注意到令 \(S = \sum a_i\) 则每个连通块的 \(x=\sum a\) 都是 \(S\) 的约数,那么 \(x\) 只有 \(d(S)\) 级别,这个值是 \(2\times 10^4\)。我们枚举 \(x\),注意到划分方式应该最多只有一种:自底至顶考虑即可。

事实上还有更简明的结论:恰好有 \(\frac{S}{x}\) 个点的子树和 \(sum_u\)\(x\) 的倍数,发现后不难证明。

根据上述这个事情还能证明一个我们很想要的东西:如果 \(p\mid q\)\(x=p,q\) 时均能划分,则 \(x=q\) 时的方案一定是 \(x=p\) 时的方案的子集。这样我们就可以直接 \(dp\),也就是 \(dp(q) := dp(q)+dp(p)\) 这样转移,然后 \(dp(S)\) 就是答案。

这样我们已经得到了一个 \(O(d(S)\times (n+d(S)))\) 的做法,但是 \(n=10^6\) 下它依旧无法通过。

对于每个 \(sum_u\),我们把他贡献到所有它的约数 \(d\) 上,且 \(d\) 也是 \(S\) 的约数。这样我们只用看每个 \(d\) 的贡献和是否为 \(\frac{S}{d}\) 即可。

由于 \(d\) 可能很大,这样并不好直接处理。我们换一种角度:枚举连通块个数,这个值是介于 \(1\sim n\) 之间的,也就是我们现在转而枚举 \(c=\frac{S}{d}\) 了,这样的合法的 \(c\) 还是只有 \(d(S)\) 个,但是就有 \(c\le n\) 了。

此时考虑 \(sum_u\) 能贡献到什么样的 \(c\)

\[\frac{S}{c} \mid sum_u \Leftrightarrow S\mid sum_u\times c\Leftrightarrow \frac{S}{\gcd(S,sum_u)}\mid c \]

第二步是因为:我们考察每个质因子的幂次,假设 \(S,sum_u,c\) 的幂次分别为 \(x,y,z\),那就有 \(x\le y+z\),也就有 \(z\ge x-y\),也即 \(z\ge \max\{0,x-y\}\)。而 \(\frac{S}{\gcd(S,sum_u)}\) 对质因子的影响就是把幂次换成 \(\max\{0,x-y\}\),这也是数论中常用的手法。

这样,我们把 \(sum_u\) 贡献给 \(\frac{S}{\gcd(S,sum_u)}\) 的倍数位置即可,且这个倍数 \(\le n\),那就很容易调和级数统计了。

时间复杂度 \(O(n\log(na))\)

记录

26. Artistic Partition

感觉 3000* 有点低了。。

没啥思路,打个表随便输点东西看看输出,看了一会儿猛然意识到 \(k\gt \log n\) 的时候一定答案为 \(n\),因为我们 \([2^i,2^{i+1})\) 这样划分所有 \(i\lt j\) 的对就都没贡献了。

思路这不是就一下子来了嘛!直接设 \(f(j,i)\) 是把 \([1,i]\) 分成 \(j\) 段的最小代价和,如何转移?注意到 \(c(l-1,r)\) 的增长永远比 \(c(l,r)\) 快(自变量为 \(r\) ),因此有决策单调性在,那么压力来到求 \(c(l,r)\),因此如果我们求 \(c(l,r)\) 的时间是 \(T\),这个问题就在 \(O(n\log^2T)\) 的时间内解决了。

看上去 \(\log^3\) 不是很行,大胆猜测 \(c(l,r)\)\(O(1)\)。看到 \(\gcd\) 就推推式子,注意到 \(\ge l\) 不是很好求,可以转成 \(\lt l\),而且还有更方便的东西在:可以看成求 \(\sum_{1\le i\le j\le r}[\gcd(i,j)\lt l]\),因为如果 \(i,j\) 有一个 \(\lt l\),那么 \(\gcd\) 的结果一定 \(\lt l\)。用 \(\frac{r(r+1)}{2}\) 减去这个就是 \(c(l,r)\)

因此令 \(F(l,r)=\sum_{1\le i\le j\le r}[\gcd(i,j)\le l]\),考虑换一下求和顺序:

\[\sum_{k=1}^{l}\sum_{1\le i\le j\le\lfloor \frac{r}{k} \rfloor}[\gcd(i,j)=1] \]

\(f(x)\)\(\phi(x)\) 的前缀和函数,则所求即为:

\[\sum_{k=1}^{l}f(\lfloor \frac{r}{k} \rfloor) \]

这显然是一个整除分块形式,因此可以 \(O(\sqrt n)\) 求出 \(c(l,r)\)

我们可以花费 \(O(n\sqrt n)\) 的时间预处理,然后做到 \(O(1)\)\(c(l,r)\),这部分比较平凡,不再赘述。然后本题做到了 \(O(n(\sqrt n +\log^2 n))\) 的复杂度。

记录

27. Equal LCM Subsets

很趣味的题。太人类智慧了啊啊。

这个恐怖的 \(4\times 10^36\) 的值域直接让大家做不了质因数分解了,顶多能做的数论相关的可能只有 \(\gcd\) 了。。

因此不太能从零到有构造两个集合:考虑构造一个极大的集合,也就是不断删去不合法的。

如果在 \(A\) 中有一个数,它的某个质因子幂次比 \(B\) 中所有的都大,那它就必须得删去;\(B\) 中同理。如果没有这种情况了,那此时两边 \(A,B\) 一定就是 LCM 相等。

结合 \(n,m\le 1000\) 突然就能做了??每次暴力找就行了,最多删 \(O(n+m)\) 轮啊。

那我们怎么快速判一个数是否要被删掉?注意到我们是不能做质因数分解的。。。。

因此只能考虑用 \(\gcd\) 搞事情:还是考虑假设在 \(p\) 的幂次上 \(a_i\) 比所有 \(b_i\) 都大。那就是 \(x \gt \max\{y\}\),但是我们不能出现 \(\max\),因为不能做 LCM;也无法转成 \(\min\),但是可以转成 \(x-y_1\gt 0,x-y_2\gt 0,...,x-y_m\gt 0\),那也就是 \(\min\{x-y_i\}\gt 0\),而 \(\frac{x}{\gcd(x,y_i)}\) 就是在做 \(\max\{0,x-y_i\}\),因此其实等价于 \(\gcd(\frac{x}{\gcd(x,y_i)})\gt 1\)。。。

这样我们会一个 \(O((n+m)^3)\) 级别的东西了,考虑用线段树维护就能支持删除,这样时间复杂度 \(O((n+m)\log n\log a)\),这一步倒是很平凡。

记录

28. Oppa Funcan Style Remastered

感觉反而比上面这个简单点。

先考虑忽略掉“都是 \(k\) 的约数”的性质,只问:给出 \(a_1,a_2,...,a_m\),能否把 \(n\) 表示成它们的非负线性组合。

这是一个经典问题:我们假设 \(a_1\) 是最小元,则可以跑同余最短路:在 \(O(ma_1)\) 的时间内解决(不需要真的建图跑最短路,只需要在每个置换环上直接转两圈就可以更新到所有答案,这是经典技巧,可以看 Alex_Wei 的相关博客)。

考虑什么时候 \(a_1\) 会很大:那也就等价于 \(k\) 的最小质因子很大。

我们此时又可以观察出:只会选择 \(k\) 的质因子。那么 \(m=O(\log k)\)

\(k\) 的最小质因子是 \(O(\sqrt k)\) 的,因此我们得到了一个单次 \(O(\sqrt k\log k)\) 的解法。

能不能把 \(k\) 的最小质因子变小?当 \(k\)\(3\) 个(或以上)的质因子是显然最小的不超过 \(10^5\),此时我们跑同余最短路就可以接受了;对于 \(2\) 个质因子的情况,可以直接解不定方程;对于一个质因子的情况,非常平凡。

最后需要特判 \(k=1\) 的情况。

记录

29. Random Isolation

好题!

考虑用期望线性性把要算的拆开:最开始想研究每个点被删的概率,但这样很难做。

考虑每次删除都对应了一个大小 \(\gt k\) 的连通块。那么我们转而对每个大小为 \(k\) 的连通块,统计它出现的概率(出现指和它相连的边全部断开了)。因为只要它出现了,就会有 \(1\) 的贡献;而每个 \(1\) 的贡献又一定对应一个这样的连通块出现,因此形成了一一对应。

那我们给定一个连通块,如何计算它出现的概率?

充要条件是每个邻接的点都已被删除,但问题是我们不能直接地给每个人赋一个被删除的时间戳,因为有些点从头到尾压根就不会被删除,而且还和选点的顺序有关。

本题最神的一步出现了:我们把问题改写一下,考虑那些 \(\le k\) 的连通块的影响:等概率随机一个排列 \(p\),然后依次考虑每个点,如果当前点的连通块 \(\gt k\) 就删除,否则什么都不做。

这样做答案不变的道理是:当前这一步后,考虑剩下的所有 \(\gt k\) 的连通块的点,我们本来是下一步随机从这里选一个删除;现在变成了有可能随机考虑掉一些 \(\le k\) 的连通块的点,然后再选择一个 \(\gt k\) 的连通块的点删除;但无论如何,考虑 \(\gt k\) 的连通块的那些点,它们在下一次有效删除时被考虑到的概率都是均等的。

这样整个问题就清晰了很多:此时我们可以把原问题变成给每个人打时间戳。那么一个连通块在某个时刻出现,当且仅当它邻接的点时间戳都在它之前。

这样,如果连通块大小为 \(a\),而邻接点有 \(b\) 个,则概率即为 \(\frac{a!b!}{(a+b)!}\)

那么我们只关心连通块的 \(a,b\) 两个属性。考虑连通块计数可以点分治:我们先来计算包含 \(1\) 的连通块,那么在 dfs 序上 dp:设 \(f(i,j,k)\) 时考虑完 dfs 序 \(\le i\) 的点,然后选了 \(j\) 个点,有 \(k\) 个邻接点的连通块个数,转移可以 \(O(1)\),这是简单的技巧。我们递归下去后由于要考虑邻接点,所以那些在当前 part 外的点是需要被考虑进去的(它们会对第三维有影响)。

在一个 part 内 dp 的时候,第三维上限是 \(n\),而前两维上限都为 \(sz\)。因此时间复杂度应该是 \(n\) 乘上点分治每次连通块大小的平方和。

这个东西也就是 \(T(n)=2T(n/2)+O(n^2)=O(n^2)\),因此时间复杂度 \(O(n^3)\)

记录

30. Make Adjacent

感觉,比 B 简单。。。。

首先来思考最小化 \(k\),如果我们钦定了最后的序列长什么样,则也就相当于我们钦定了每个人换到了哪个位置。具体的如果第 \(2i-1\)\(2i\) 个人钦定为 \(x\),那么原序列中左边的那个 \(x\) 就要出现在 \(2i-1\),右边的那个 \(x\) 就要出现在 \(2i\)

那么交换次数就是这个排列的逆序对。我们考虑最小化逆序对。

把原序列里 \(x\) 的两次出现看成一条线段 \([L_x,R_x]\),那么我们就是要找到一个排列线段的方式最小化逆序对。

根据直觉按照 \(R\) 排序即可,也不难通过邻项交换验证。这样我们解决了最小化 \(k\)

在邻项交换的时候我们发现:假设两个区间 \([L_1,R_1]\)\([L_2,R_2]\) 满足 \(R_1\lt R_2\),那么如果第一个区间被第二个区间包含,我们可以互换他们的位置(也就是按照 \(R\) 排序的话是第一个区间在前面,但是第二个区间在前面也不改变 \(k\));否则我们一定不能互换他们的位置。

那现在考虑每个区间有一个数,我们要找到一个区间的排列,使得把数写出来后最小化其字典序。考虑从前往后确定每个位置是谁:那么我们就是从能交换到开头的区间里找一个数最小的。

什么情况下一个区间能交换到开头?当且仅当前面的每个区间都被它包含。

这样我们就得到一个 \(O(n^2)\) 的做法,每次暴力实现上面的过程就可以了。

考虑包含等价于 \(L_2 \lt L_1\)\(R_2\gt R_1\),又因为我们就是按照 \(R\) 排序的,那当且仅当 \(L_i\) 是前缀 \(L\) 的最小值的时候,区间 \([L_i,R_i]\) 才能被换到前面来。

现在变成了这样一个数据结构问题:

维护二元组序列 \((x_i,y_i)\),支持单点删除,查询所有 \(x_i\) 是前缀 \(\min\) 的位置里 \(y_i\) 的最小值。

这种前缀 \(\min\) 相关查询是经典问题,套用楼房重建的做法即可。时间复杂度 \(O(n\log^2 n)\),实际上跑得很快,不输很多 \(O(n\log n)\) 的官解实现。

记录

31. Gem Island 2

首先我们忽略掉每个人初始拥有的那个人,也就是令 \(a_i:=a_{i}-1\),最后答案加上 \(r\) 即可。

我们给每个宝石分配一个 \(1\sim d\) 之间的标号,表示它是第几轮出现的。

对于每个状态 \(a_1+a_2+...+a_n=d\),我们都有 \(d!\) 种方式给每个宝石打标号;因此每个状态的出现概率相同。都是 \(\frac{d!}{\prod_{i=0}^{d-1}(n+i)}\)

现在变成这样一个问题:对所有的非负序列满足 \(\sum a_i = d\),求其前 \(r\) 大的 \(a\) 之和。

对于一个确定的序列,我们可以枚举一个 \(v\):然后假设恰好有 \(x\)\(a_i\ge v\)。我们就把答案加上 \(\min\{x,r\}\)。那么注意到 \(x\le \frac{d}{v}\),所以我们的总量不会超过 \(d\ln d\),这是好的。

考虑恰好有 \(x\) 个还是非常困难的一件事,我们只能容斥掉。对于一个确定的 \(v\),设 \(f(x)\) 是恰好 \(x\) 个,\(g(x)\) 是钦定 \(x\) 个。则我们首先得到:

\[g(x)=\dbinom{n}{x}\dbinom{d-vx+n-1}{n-1} \]

并且有反演关系:\(f(x)=\sum_{y\ge x}(-1)^{y-x}\dbinom{y}{x}g(y)\)

因此我们原本要求:

\[\sum_{v=1}^{d}\sum_{x=1}^{d}f_v(x)\times\,min\{x,r\} \]

现在就要求:

\[\sum_{v=1}^{d}\sum_{x=1}^{d}\min\{x,r\}\times\sum_{y\ge x}(-1)^{y-x}\dbinom{y}{x}g_v(y) \]

考虑交换求和顺序来应对这个式子,我们注意到 \(g_v(y)\) 非常难处理,所以它应当是一个排在最前面枚举的东西:

\[\sum_{y=1}^{d}\sum_{x\le y}(-1)^{y-x}\min\{x,r\}\dbinom{y}{x}\sum_{v=1}^{d}g_v(y) \]

考虑 \(\sum_{v\ge 1}g_v(y)\) 就是 \(\dbinom{n}{y}\times \sum_{v\ge 1}\dbinom{d-vy+n-1}{n-1}\)。对于后面这个式子:令 \(h(x)=\dbinom{d-x+n-1}{n-1}\),则我们求的就是 \(h(x)\)\(y\) 处的狄利克雷后缀和(其实也就是 \(H(x)\) 是所有 \(h(ix)\) 的点值和),类比高维后缀和的过程:枚举质数 \(p\),并且从大到小考虑所有 \(p\) 的倍数即可。时间复杂度同埃筛是 \(O(d\log\log d)\) 的。这样我们把最里层的和式杀掉了,也只用求:

\[\sum_{y=1}^{d}\sum_{x\le y}(-1)^{y-x}\min\{x,r\}\dbinom{y}{x}H(y) \]

那么把一些只和 \(y\) 相关的提取到外层:

\[\sum_{y=1}^{d}(-1)^{y}H(y)\sum_{x\le y}(-1)^x\min\{x,r\}\dbinom{y}{x} \]

现在压力来到第二层和式。我们缓一缓。。。


对于 \(S(n,r) = \sum_{i=1}^{n}(-1)^{i}\min\{i,r\}\dbinom{n}{i}\) 来说,我们最先想到的手法是讨论 \(i\)\(r\) 的关系,为此,很容易发现我们需要求出另一个和式:\(T(n,k)=\sum_{i=1}^{k}(-1)^{i}i\dbinom{n}{i}\)

利用吸收恒等式,注意其等价于 \(-n\sum_{i=0}^{k-1}(-1)^i\dbinom{n-1}{i}\)

这样我们需要求出 \(Q(n,k)=\sum_{i=0}^{k}(-1)^{i}\dbinom{n}{i}\) 的值。

这里的 \((-1)^i\) 非常重要,不然变成了组合数行前缀和问题。

考虑使用上指标反转:

\[\sum_{i=0}^{k}\dbinom{i-n-1}{i} \]

平行求和,启动:

\[=\dbinom{k-(n+1)+1}{k} \]

这样我们就在 \(O(1)\) 的时间内求出了第二层和式的值,时间复杂度 \(O(n+d\log\log d)\)

这里需要注意的是:我们求组合数的时候可能会出现上指标负数的情况,需要用上指标反转变成 \(n,m\ge 0\) 的情况。

记录

posted on 2023-09-03 13:28  Cry_For_theMoon  阅读(308)  评论(6编辑  收藏  举报