Cry_For_theMoon  

十月了。

1. 杀蚂蚁简单版

我知道我的做法很唐,不要攻击我😭

首先考虑 \(s=2\) 的部分分:当 \(s\) 固定的时候我们直接算出每个点被经过的期望次数,然后把 \(u\rightarrow v\) 路径上的期望 \(E\) 加起来即可。

对于期望次数:有式子 \(E(u) = \sum_{(u,v)\in e\land v\neq 1}p(v\rightarrow u)\times E(v)+[u=s]\),其中 \(p(v\rightarrow u)\)\(v\) 一步走到 \(u\) 的概率。这是一个高斯消元的形式,可以用树上高消在 \(O(n\log)\) 的时间内完成。这样我们解决了 \(s\) 固定的情况。

考虑 \(s\) 不定的情况:我们把询问离线然后尝试换根。这里首先需要知道树上高消的本质:我们把每个点(除了根)的 \(E(u)\) 表示成了关于 \(E(fa_u)\) 的(严格)一次多项式,然后 \(E(s)\) 可以直接求得;最后从顶至底回代。

我们设 \(x=E(s)\),则 \(s\) 的一个儿子 \(v\)\(E(v)\) 就应该是一个一次函数 \(k_v\times x+b_v\) 的值;而 \(v\) 的一个儿子 \(w\)\(E(w)\) 就应该是 \(k_w\times E(v)+b_w\) 的值。换言之我们是在自上往下不断把 \(x\) 替换为关于 \(x\) 的一个一次函数。

把这个一次函数称作一次变换:定义 \(FG(x)\) 表示 \(G(F(x))\)(对于更多个一次函数也同理)。那我们的 \(E(u)\) 就是:把 \(s\rightarrow u\) 的路径上的点 \(v_1,v_2,...,v_k\) 依次写出来,那就是 \(E(u)=F_{v_1}F_{v_2}...F_{v_{k}}(x)\)

当我们换根 \(s\rightarrow v\) 的时候,假如 \(u\)\(v\) 子树内一点,则它对应的式子会少掉最后的一个变换 \(F_{1}\)。我们左乘上它的左逆 \((F_1)^{-1}\) 即可;假如 \(u\)\(v\) 子树外一点,则它对应的式子会额外多出一个变换 \(F'\),我们左乘上即可。

因此我们需要维护每个点的一个变换 \(F_i\),并且支持区间把 \(F_i\) 变为 \(GF_i\)。注意到一次函数的复合是容易的,因此这也是容易的。

然后求树上路径的和,也就是在分别求树上路径的变换和,直接用树剖维护即可。时间复杂度 \(O(n\log^2 n)\)

记录

2. Levko and Game

很高妙的图论题!

先来判断能不能让第一个人获胜。

首先可以注意到我们要么把边权设为 \(L\),要么设为 \(R\)。我们不妨初始全部设为 \(R\)

则第一个人要么已经能够获胜,否则我们必须调整一些边权。

我们能调整一条边 \(u\rightarrow v\)\(R\) 变为 \(L\),当且仅当第一个人到 \(u\) 的距离比第二个人到 \(v\) 的距离要近,这样的话:第二个人一定不会走这条边,否则第一个人也走这条边就已经赢了;那么我们为了让第一个人的最短路尽可能低,就把这条边设置成 \(L\);否则,我们可以证明改这条边后不可能让答案变得更好:因为假设第一个人的路径走了这条边,第二个人也走一定会让第一个人无法获胜。

我们不断这样能调整就调整,最多调整 \(k\) 次后结束。如果无法获胜,用相同的手法判断能否平局。

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

记录

3. Upgrading Cities

怎么图论题都这么高妙。

我们先考虑关键点怎么求:显然其不强于什么 DAG 两点可达性,但是用 bitset 去维护定然会超时。

由于是 DAG,考虑研究拓扑排序相关的性质:一个性质是这样的点拓扑序一定固定。

那么我们可以随机若干个拓扑序,如果一个点始终位置不动就是关键点。

那么次关键点呢?多次随机判断其位置是否极差 \(\le 1\) 看上去很对,但实际上并不能通过:理由是一些非次关键点在随机找拓扑序的时候非常难以被区分出来,构造方式可以大家自己想一下:只要让一车它走不到也不能被走到的点,以极大的概率一定出现在这个点之前(或之后)就可以了。

考虑一些确定性的做法:对于关键点,在拓扑排序中它永远是单独出现在当前队列的。

这个条件必要而不充分:我们研究样例 \(1\) 就会发现,如果先删去 \(6\),则 \(2\) 也会在拓扑序始终单独出现在当前队列里。看上去我们陷入了死胡同。

注意到此时还有一个性质:就是没有入队的所有点都能被队列里的这个唯一点走到;而反之其余的所有点一定不能被队列里的唯一点走到。

那么我们正反各拓扑一次,分别可以算出这些点能走到的点(以及能被走到的点),如果相加起来为 \(n-1\) 那么这个点就是关键的;此时我们找到了描述关键点性质的充要条件。

那么次关键点呢?我们还是考虑做两次拓扑,每次都找到一个点能到达多少个点。但此时队列大小为 \(2\) 并不意味着这两个点不合法:有可能对于其中一个点来说,删去这个队列里另外一个点,它就是合法的。

假设队列两个点是 \((u,v)\),如何判断删去 \(v\) 以后 \(u\) 是合法的?首先不能有两个时刻队列大小都为 \(2\) 且分别出现 \((u,v),(u,w)\);否则我们假设删去 \(v\) 以后还有一个点 \(w\) 不能被 \(u\) 走到:考察所有这样的点 \(w\),必定有一个能被 \(v\) 直接走到:那么我们只需要考察 \(v\) 的所有后继,是否此时只和 \(v\) 有连边即可。

这样就在 \(O(n+m)\) 的时间内完成了检查。

感觉这个题还是非常思维的。

记录

4. Football

神题!

发现样例是把所有边全选上了,所以我们猜测一定能选满。也就是给定任何一张图都能构造的意思。

先考虑 \(k=2\) 的情况:发现是经典欧拉回路问题:对于奇数点我们将其和虚拟点 \(0\) 连边,然后对每个连通块都跑欧拉回路,按顺序依次交替分别 \(1,2\) 两种颜色,最后删掉虚边。可以证明这样就让每个点的两种颜色差 \(\le 2\)

如果一个点不是回路的起点,它进入一次,紧接着就会出去;那么这两次的颜色是不同的。因此它的颜色相等。

否则这个点会走若干个次环路。如果走偶环,则出去和进来的颜色是不同的;如果是奇环,则进来和出去的颜色是相同的。但是我们注意到假如连着走了两个奇环,那么如果第一个奇环两次都是 \(1\),第二个奇环两次就会是 \(2\);这样相差 \(2\)

那么再考虑删除的虚边:注意到只有原本奇数度数点才会删除一条边,而此时他和 \(0\) 连通,我们一定是用 \(0\) 作为起点的,因此这个点不是起点 $\rightarrow $ 原本两种颜色数量相等 $\rightarrow $ 删去一条边后两种颜色差 \(1\)

这样我们完成了 \(k=2\) 的构造。对于一般情况:我们考虑任意给图染色,然后不断找到一个不合法的点 \(u\):把他的最大颜色和最小颜色 \(x,y\) 拿出来,用 \(k=2\) 的方法调整所有 \(x,y\) 两种颜色的边。不断调整,则最后一定能调整出一组合法解。

为了优化效率:考虑初始随机染色,这样需要调整的对就不会太多,可以轻松通过。

记录

5. Gold Experience

非常神仙的构造!并且 sjy 的解法也非常优秀。

考虑用补图来描述:也就是如果 \(\gcd=1\) 我们连边。

则我们要么找一个大小为 \(k\) 的独立集;要么找一个没有孤点的大小为 \(k\) 的导出子图。

直接贪心!从前往后能加就加;如果有大小为 \(\ge k\) 的独立集直接赢麻,否则我们的独立集有 \(a\lt k\) 个点,剩余的每个点都至少和独立集的一个点有连边。把点分成 \(a\) 类,注意到 \(2a\lt n\) 因此必定有一类至少有三个人。我们按照类的大小贪心从大往小考虑,考虑第一次前缀和 \(\ge k\) 的位置,如果最后一个选的类至少选出了两个则我们就找到了一组解;否则我们把第一组少选一个,第二组多选一个即可。这样我们一定找到了解。也就得到了一个 \(n^2\) 级别的构造方式。

现在来考虑如何加速过程:首先是判断能不能加入一个点进入独立集,那就是给一个集合,支持加数,以及给一个数问有多少个互质的。这个直接莫反:可以做到 \(d(a)\),由于只关心是否互质所以可以进一步做到 \(2^{\omega(a)}\)

再来考虑 \(n-a\) 个人会归于哪一类:套用上面的操作,直接整体二分即可。

这样时间复杂度 \(O(n\log n\times 2^{\omega})\)。常数很小。

记录

6. Pork barrel

先不考虑 \(R\) 的限制:我们从大往小考虑每条边,在生成树中加入它,并且删去原树上两点路径的最大边即可,这样在 \(O(nm)\) 的时间内维护出了每个 \(L\) 对应的 MST。

考虑现在还有边权 \(\le R\) 的限制:因此我们对每个时刻维护一颗 seg,删除/加入某条边的时候在 seg 对应位置修改;使用主席树即可。

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

记录

7. King’s Inspection

我去,有向图哈密顿回路。

怎么 \(m\le n+20\) 呀?

注意到:如果有一个点 \(u\),出度为 \(1\),则设其连向 \(v\):当我们走到 \(u\) 的时候,下一步必须立刻走 \(v\),因此我们删掉 \(v\) 的其它入度,然后把 \(u,v\) 合并成一个点;类似地,如果 \(u\) 入度为 \(1\),我们做相同的事情。

则最后要么只剩一个点,要么每个点出入度都为 \(2\)

如果真的有哈密顿回路:则考虑如下构造,在一个环(也就是最后的答案基础上)加若干根弦,这样的话每条弦能让一个点的出度加一,一个点的入度加一;最多只能让 \(20\) 个点出入度为 \(2\)

然后我们状压即可。令 \(v=m-n\),则复杂度 \(O(2^v\times v^2)\),可以轻松通过。

记录

8. Dancing Disks

非常好的构造题。

假如我们能让两个格子的若干个数分别都是有序的(同时升序/降序),那我们选择一个他们都能走到的格子,然后就可以把两个序列归并起来。

考虑对于一个格子 \((i,j)\) 而言,可以把所有满足 \(x\le i,y\le j\)\((x,y) \neq (i,j)\) 的格子的序列都归并到这个位置。

因此我们设 \(f(i,j)\) 是能把多少个格子移动到 \((i,j)\),则有 \(f(i,j)=\sum_{(x,y)\lt(i,j)}f(x,y)\)

初始 \(f(1,1)=1\)。那么计算一下只能排序约 \(2.5\times 10^4\) 个盘子。但是注意到我们此时每次只动了一个盘子。考虑每次动多个盘子会发生什么。

我们发现 \(f(1,2)=f(2,1)=1\)。但是我们可以做到令其为 \(2\):如果我们把两个按顺序取出就是我们想要的顺序,则直接全部一起取出,否则分两次取出即可。

这样 \(f(6,6)\) 就大于 \(4\times 10^4\) 了,可以通过本题。

操作步数是不超过 \(10n\) 的。

记录

9. Balanced Diet

很清新的好题。

注意到根据题目限制:任何时刻,一个糖的出现次数上下界 \(L,R\) 相差不超过 \(1\)

我们考虑满足从前往后扫描每个时刻,如果有糖原本 \(cnt=L\),这个时刻 \(L\) 增加了,则如果有多个一定失败,否则我们这一天必须选这个糖;否则我们一定选择一个 \(cnt=L\)\(L=R-1\) 的人,如果没有一定失败,否则我们会选择 \(L\) 增加的时间最靠前的那个人,正确性容易证明。

上述过程可以拿堆维护。注意到由于 \(\sum R\) 是和天数同阶的,所以总的变化次数和天数也是同阶的。

我们猜测存在一个阈值 \(V\),一旦天数大于这个,就一定能无限下去。

\(V=10^6\) 发现已经可以通过,我们来分析一下其中的道理:当天数是 \(\sum a\) 的倍数的时候,注意到每个人的 \(L,R\) 都是相等的,也就是得到了一组确定的解。

只要我们的天数里有两次都是 \(\sum a\) 的倍数,我们就肯定能不断重复这段时间内的操作无穷做下去。

注意到 \(\sum a \le 10^5\),因此其实 \(V=10^5\) 就可以了。

记录

10. Max-digit Tree

一万年没更新做题记录了,先写个厉害题的。

考虑大概算法应该就是:树上带根连通块套用 dfs 序 dp 的套路,问题是我们好像都不太会快速判一个串是否出现过,考虑那就大概是个 dp 套 dp 的过程。

所以如果能解决判定一个串是否出现过这个题就应该是做完了,并且我们知道大概他就是用 dp 的方式去判。

观察一下 \(a\) 序列,会发现只有末位是在跳的,去除末位的话这是一个相邻两项差不超过 \(1\) 的递增序列。

也是容易证明的:因为我们 \(a_n\rightarrow a_{n+1}\) 最多加 \(k-1\),也就是至多进位一次。

这点是本题的突破口:末位和末位以外的部分有本质区别,也就是我们判定一个串是否出现,它的前 \(len-1\) 位一定是出现过的,唯一的问题就是末位可能会对不上。

因此考虑把前 \(len-1\) 位喂给我们的检查函数,然后得到最后的可能的那些末位集合,再判我们询问串的末位是否出现在这个集合里,这个长得就非常有自动机的那种感觉。

我们来研究前 \(len-1\) 的变化,如果是每次 \(+1\) 那其实挺麻烦的:因为我们是关注这里的最大数位的,但是你 \(+1\) 后最大数位不太能维护。

所以从低位开始喂数字不太可行,考虑从高位开始喂:就是我们可以设 \(dp(i,j,k,l)\) 表示现在第 \(2\sim i\) 位都是 \(0\),然后 \(i+1\) 往后的位里的最大数位是 \(j\),目前的末位是 \(k\),我们不断增加,第一次让第 \(i\) 位变成 \(l\),且 \(2\sim (i-1)\) 位都是 \(0\) 的时刻,此时的末位是多少。

那我们其实就是先让第 \(i\) 位变成 \(l-1\),因此 \(k:=dp(i,j,k,l-1)\);然后先让 \(i-1\) 位变成 \(k-1\),再让 \(i-2\) 位变成 \((k-1)\),。。。,直到 \(2\sim (i-1)\) 位都变成 \(k-1\) 了,然后此时我们再不断在末位加数使得最后产生一次进位。直接利用之前算出来的 dp 值维护过程中的 \(k\) 的变化即可!

这个 dp 朴素做大概是 \(n^2k^3\) 的,但是比较容易优化到 \(nk^3\)

那么回到本题我们把这个过程套进 dfs 序上就好了,也就是 \(f(u,i,j,k)\) 表示目前到了 \(u\),然后还要填 \(i\) 个位置,前面的最大值是 \(j\),当前的末位是 \(k\) 的方案数。这部分是 \(n^2k^2\) 的。

因此总复杂度 \(O(nk^3 + n^2k^2)\)

11. Math, math everywhere

首先考虑这样一个弱化弱化版本:\(s=11\)

则考虑相当于对于任意一个质因子 \(p\) 而言,\(x\equiv p\) 不能是 \(0/p-1\),这也是充要的。

我们知道方程组 \(\begin{cases}x \equiv b_i\pmod{p_i} \end{cases}\)\([0,M)\) 范围内(其中 \(M\)\(\prod p_i\))有且仅有一组唯一解,其中 \(b_i\in[0,p_i)\)。因此假设 \(N=M\),则我们就得到 \(\prod (p_i-2)\) 个解;注意到 \(N\) 一定是 \(M\) 的倍数,因此对于 \(N\neq M\) 的情况我们直接乘上 \(\frac{N}{M}\) 即可,也就是 \(K=\prod p_i^{a_i-1}\)

因此我们现在只来考虑 \(N=M\) 的情况。

考虑沿用上面部分的想法:我们设原串为 \(1\) 的位置是 \(X\),然后钦定 \(X\) 的一个超集 \(Y\) 这些位置全为 \(1\),其它位置忽略,容斥系数 \((-1)^{|Y|-|X|}\)。那么相当于是说对于一个 \(p_i\)\(v\in X\),不能有 \(x\equiv -v\pmod{p_i}\)。相当于我们 ban 掉了 \(|Y|\) 个位置,因此 \(\prod (p_i-|Y|)\) 就应当是此时的答案。

但其实这并不全对:假如 \(p=3\)\(\{1,4\}\subset Y\),则我们看到 \(x\) 只是不能和 \(1\) 这一个值同余,而不是两个值。

事实上问题就是出在如果 \(p\lt m\) 那么我们可能有两个 \(1\) 的位置 \(\bmod p\) 是相同的,所以我们 ban 掉的就不是 \(|Y|\) 个位置而是 \(\le |Y|\) 个位置了。

现在考察 \(\le 40\) 的所有质数(共有 \(12\))个,考虑换一种方式计算答案:

我们刚才是钦定 \(Y\) 然后算方程解数;考虑交换求和顺序,我们枚举一组方程的解然后算有多少种合法的 \(Y\)。因此考虑按顺序为每个 \(p_i\) 钦定它的 \(b_i\),则我们要求 \(S\) 中所有 \(\bmod p_i = b_i\) 的下标都不能填上 \(1\)。因此设 \(dp(i,A)\) 表示考虑完了前 \(i\) 个质数,然后集合 \(A\) 内的下标不能填上 \(1\),此时的一个方案数。当我们算完 \(dp\) 后,那些 \(\ge m\) 的质数就非常容易处理:因为直接枚举最后有多少个位置填的是 \(1\) 即可。

直接暴力 dp 肯定复杂度不对:我们猜测状态数不是很多,并且在 \(\{2,3,5,7,...,31,37\}\) 这个集合下状态数真的不是很多,可以给出这样一个分析:因为我们第一步为 \(2\) 选定 \(b_i=0/1\) 的时候就意味着 \(A\) 的大小已经是 \(\frac{m}{2}\) 了,所以剩下的集合往后肯定不超过 \(2^{\frac{m}{2}}\) 个。但是没人说一定有 \(2\) 啊?事实上我们把 \(2,3\) 去掉的时候发现状态数就顶满了,远远超过 \(2\times 10^7\),直接寄麻了。(事实上这个做法就是赛时的 std,但是赛后被 KAN 叉了,第 \(82\)\(83\) 组 数据都是在做这个事情。)

没有下面这部分的话其实真是个爵士好题。。。

发现只考虑 \(\le 19\) 的质数的时候状态数能接受:是 \(2\times 10^6\) 级别的。那我们算完 \(23\) 的时候就有 \(10^7\) 多一点的状态个数了,我们此时先不存储这些状态,考虑后面还有三个数 \(29,31,37\)

先考虑 \(29\):注意到对于 \(29\) 而言,如果我们钦定解 \(b_i\)\([11,29)\) 之间,那其实有且仅有一个位置 \(b_i\) 是满足 \(\bmod 29 = b_i\) 的,因为 \(b_i+29\)\(\ge 40\) 了。所以我们不太需要存储这中间的数是否在 \(A\) 里,我们只关注 \(|A|\)。因此我们可以只记录头尾分别 \(11\) 个数是否在 \(A\) 中。

对于 \(31\) 而言同理,记录头尾 \(9\) 个数;\(37\) 就记录头尾 \(3\) 个数。所以我们算完 \(23\) 的时候就直接扔进 \(29\) 的那个 \(2^{22}\times 18\) 的 dp 数组里就好了。

然后 \(\le 23\) 的质数那部分 map 太慢了,所以需要手写哈希表来存储。并且本题对空间的要求很严格。大概 400MB 左右卡过去了。。。

记录

12. Shift and Decrement

好题,ucup Taipei 的 C 和这个很类似。

首先考虑枚举除二的次数 \(c\),则我们可以在第 \(1\sim c\) 次除法前做若干次减一,也可以在做完后再做若干次减一。

首先注意到我们只会在某一次除法前做一次减一,因为减两次再除能被除了后减一次替换掉。

如果我们在这 \(c\) 次除法前一次都不减,显然 \(x\) 最后会变成 \(\lfloor \frac{x}{2^c} \rfloor\);如果我们每次都减,那这个值最多也只会 \(-1\),事实上如果我们在第 \(i\) 次除法前减一了那就是等价于把每个 \(x\) 都减去了 \(2^{i-1}\)。所以这 \(c\) 次是否减一能和 \([0,2^c)\) 中的数形成一一对应,设这个值为 \(o\)

如果我们按照 \(x\bmod 2^c\) 排序,那最后会减一的一定还是段前缀。

我们枚举这个前缀,则 \(o\) 就有一个被确定的范围,我们需要在这个范围内找到一个 \(1\) 最少的 \(o\),这样就能用最少的前缀达到我们想要的效果。找到以后,对于这个序列,我们如果还剩 \(a\) 次操作,就可以把每个数都同时减去一个 \(\le a\) 的值。我们一共得到 \(O(n\log)\) 个这样的数集以及对应的 \(a\),对每个本质相同的数集(也就是全部减去最小值后相等的集合)我们相当于是在做区间求并算出最后会有多少种可能的集合。

对于 \([L,R]\)\(1\) 最少的数,找到 \(L,R\) 的 LCP 长度,设为 \(x\),则前 \(x\) 位必须相同,第 \(x+1\) 位往后要么全 \(0\),要么 \(x+1\) 位填 \(1\) 后面填 \(0\)。可以 \(O(1)\) 解决。

这样我们在 \(O(n^2\log)\) 的时间内解决了此题。

记录

13. Digit DP

有两个弱化方向:序列长度 \(N\) 是正常范围(\(10^5\)),或者开始 \(a_i=0\)

对于第一个弱化:假设我们要从 \(b_1,b_2,...,b_n\) 里选三个不同的位置相乘再求和,则令 \(s_i = \sum_{j=1}^{n}b_i^j\),显然答案为\(\frac{s_1^3-3s_2s_1+2s_3}{6}\)。那我们支持区间加,维护区间零一二三次方和即可。

对于第二个弱化:我们直接把修改和询问的坐标都离散化下来,这样就是每个点都对应一个区间 \([l,r]\) 然后带个权重 \(w_i = r-l+1\) 而已。

现在来考虑解决一般问题,棘手的情况在于每个离散化后的区间(也就是每个点)是有初值的。

显然我们只需要维护每个区间初始的 \(p\) 序列的一次/二次/三次方和。拆成前缀信息相减。

对于 \([0,R]\) 内的数的 \(p\) 序列的 \(k\) 次方和,我们有一个 \(O(\log R\times k^2)\) 的数位 dp:直接考虑把 \(k\) 次方组合意义化成选 \(k\) 个位置出来,那么就是 \(dp(i,0/1,j)\) 表示从高往低前 \(i\) 位,是否确定 \(\lt R\),选出了 \(j\) 个位置的和。

这样我们的预处理就是 \(O(qn)\) 的,而单次修改查询都是 \(O(\log q)\) 的,所以其实 1s 都足够充裕了。

记录

14. Jellyfish and OEIS

题解还是简单点好。

先考虑容斥,大家都能想到。

发现如果两区间相交不包含则能拆成三个不交的区间,但若包含关系出现则没有好的性质。套路地考虑建出树形关系。设 \(f(L,R)\) 表示区间 \([L,R]\) 内部的答案,显然有些位置不被子树覆盖到,这些位置是自由的。还会有若干个连续区间,这些区间可能是一些更大的区间拆开得出的。此时容斥系数的设置变得非常棘手。

我们将证明我们不考虑区间有相交的情况即可,tzc_wk 给出了一种双射证明。我的想法是再对我们新产生的问题套一层容斥:因为实质上是给了若干个连续的区间,合法的方案要求每个区间都被覆盖到,那不妨容斥掉,也就是钦定一些区间不被覆盖,此时剩下的若干个连续子段,每个左端点都能任意选择一些右端点。但是只要有一个右端点可选,那不选是 \(1\) 选是 \(-1\) 贡献直接变成了 \(0\)。所以剩下的每个区间 \([l,r]\) 都应该满足 \(r\gt m_l\)

所以每个区间都带 \(-1\) 的容斥系数,而如果 \(r\gt m_l\) 又有 \(1\) 的容斥系数。所以当且仅当 \(r\le m_l\) 的时候这个容斥系数和才非零。

然后就做完了,时间复杂度 \(O(n^4)\),常数极小。

记录

15. CEN-Price List

我们直接启动 dijkstra 的过程:考虑 \(a\) 类边的松弛是平凡的,而当我们取出一个点 \(u\) 到时候,对于所有的点 \(w\) 满足 \((u,v)\)\((v,w)\) 都有连边且 \((u,w)\) 没有连边,我们都会用边权 \(b\) 去松弛。称这样的松弛是非平凡的。

显然一个点被非平凡松弛一次后,就不需要再被非平凡松弛了。所以考虑可以用 set / dsu 维护每个点没有被非平凡松弛过的邻点,然后我们暴力遍历 \(v\) 的所有邻点并尝试松弛 \(u\rightarrow w\) 即可。

如果没有 \((u,w)\) 没有连边这条限制,则每个点最多被这样检查一次,那么复杂度就是 \(O((n+m)\log)\)。现在考虑出现这种失败松弛的情况意味着我们找到了一个三元环 \((u,v,w)\),而众所周知无向图三元环个数是 \(O(m\sqrt m)\) 级别的,因此假设我们能 \(O(1)\) 判边是否存在,就能做到 \(O((n+m)\log + m\sqrt m)\)

而注意到我们是取出 \(u\) 再判断 \((u,w)\) 是否存在的,所以每次取出 \(u\) 的时候,直接标记它的所有邻点。这样 \(w\) 被标记等价于 \((u,w)\) 存在。

记录

16. Edycja

好像是以前 zimpha 发出来的,这几天才解决掉。

先考虑没有第一种操作咋办,这个在 USACO 银组之前做过,就是我们考虑假设字符 \(a\) 全部变成了 \(b\)(显然只会变成一种字符),那么就连 \(a\rightarrow b\),这里如果有自环我们不连边,并且当我们称环的时候,是不算自环的。

注意到对于一个连通块而言:它要么是树,要么是基环树。

如果是树,那么显然我们恰好花 \(m\) 次操作就够了,这里 \(m\) 是边数。

如果是基环树,我们其实也花 \(m\) 次操作就够了。这个可以手玩得出。

对于一个环,我们发现我们需要 \(m+1\) 次操作,并且是需要换出去一次的:所以如果 \(26\) 个字母都是环 / 自环那其实是无解情况。

有第一种操作以后,我们其实就不会有无解了,且一个字符 \(a\) 可能最后会变成多种字符,但我们只能保留一种。

那相当于是:每个点可以自由选择出边(或者自环,也就是不连),\(f_{i,j}\) 表示 \(i\) 字符连向字符 \(j\) 的代价(代价也就是其它字符都要用第一种操作解决)。那我们就是每个 \(i\) 都选一个 \(f\) 出来,使得 \(\sum f\) 加上这张图的额外代价最小。

假如没有环额外带来的影响,我们其实贪心对每个 \(i\) 选择 \(f_{i,j}\) 最小的人即可。考虑这个解 \(G\) 的形态:我们可能会把一些环上的 \(f\) 改变,使其变成基环树 / 树,从而去掉额外的一次 \(+c\) 代价。

注意到还会产生一个问题:就是如果我们重新决策的过程中产生了新环该怎么办?

这种情况下一定这个新环上有一个人的 \(f\) 不是最小的,我们换回来,则这个环变成了基环树,且 \(\sum f\) 还变小了,因此一定不会出现连成新环的情况。

因此可以直接设 \(dp(i,mask)\) 表示我们考虑了前 \(i\) 个字符,\(mask\) 集合内的环已经被破开的答案。注意到最多只有 \(13\) 个环所以是可以接受的。

一个 corner case 是:注意到如果初始的 \(G\) 全部由环 / 自环构成则是无解的,这时候就算修改 \(f\) 的选择不优,也必须硬着头皮选。因此需要记录一维 \(0/1\) 表示当前的 \(G'\) 是否和 \(G\) 相同。

复杂度 \(O(\Sigma 2^{\frac{\Sigma}{2}})\)

记录

17. Drazil and His Happy Friends

这个题初一的时候 cjq 在校内模拟赛就搬过,是极少没在场上做出来的题。cjq 可能因此觉得我数学基础欠佳。。

现在看感觉还是比较平凡的。

考虑把男生编号为 \(A,B,C\),女生编号为 \(0,1,2\)。则我们会 \(A0,B1,C2\) 这个顺序配对下去。

考虑对于 \(A\) 来说,他第一次和 \(0\) 配对,第二次和 \(n\bmod m\) 配对,第 \(k\) 次和 \((k-1)n\bmod m\) 配对。

和它配对的人,形如 \(kn\bmod m\),众所周知这样的关系构成 \(\gcd(n,m)\) 个置换环。

现在我们假设 \(n\le m\),则对于每个置换环,环上的每个点代表一个女生,部分点上挂了一个标签,这个标签代表一个男生。初始一些点 / 标签为 \(1\)。我们每次按顺序选中一个标签,并且把这个标签向后放一个位置。然后如果这个标签和这个点有一者为 \(1\),另一者也会变成 \(1\)

那么显然,每个环是独立的。如果这个环有至少一个点或者标签是 \(1\),就一定在有限步数内完成目标,否则一定无解。因此环数 \(\gt x+y\) 直接无解。

虽然环长可能达到 \(10^9\),但是关键的位置只有 \(x+y\) 个。我们对于标签和点分开来考虑。

对于一个初始为 \(0\) 的标签 \(x\) 而言:

  • 他只关注向后第一个初始为 \(1\) 的标签 / 点的位置。并且他在时刻 \(x\) 被激活,每走一次都要经过 \(n\) 轮才能行动。

对于一个初始为 \(0\) 的点 \(y\) 而言:

  • 首先我们假设位置 \(y\) 的标签(如果有)不为 \(1\),这种情况需要我们特判。否则我们考虑他向前第一个初始为 \(1\) 的标签 / 点的位置,如果向前找到的是为 \(1\) 的点,则再向前找到第一个标签(这个标签初始不一定是 \(1\)),那么我们就是要把这个标签移动到这个点处。

因此我们找出环上所有初始为 \(1\) 的环长和标签位置后,直接对每一段考虑最靠劣的标签(也就是位于这一段最开头的)和最劣的点(也就是这一段最结尾的)即可。需要利用 exgcd 辅助计算,这里略去相关细节。

时间复杂度 \(O((x+y)\log)\)

记录

18. Tubular Bells

好妙的交互啊。

首先我们能知道的就只有两两的 \(lcm\),那么假设我们全部知道了如何去还原?找到最大的一对,他一定是由 \(r\times (r-1)\) 组成的,然后注意到有个性质就是只有 \(a_i=r\) 的位置满足所有 \((i,j)\) 的答案都是 \(r\) 的倍数(那个 \(r-1\)的哥们不能满足这个),所以我们能算出 \(r\)\(r-1\) 的位置,然后我们去掉和 \(a_r\) 相关的即可。

因此很重要的一点是如果 \(\frac{n(n-1)}{2}\le 5000\) 我们直接就用这个暴力,这样 \(n\le 100\) 都能解决了,现在区间就非常大。这个时候启示我们使用一些随机化手段。

可以发现 \([mid,r]\) 这一段此时一定存在一个质数,如果能问出这个 \(2p\ge r\) 的质数位置,则我们花 \(n-1\) 次就能问出其他位置了,这也是 \(n+5000\) 的由来。那现在我们就要在 \(5000\) 次内问出这个大质数位置 \(p\)

直接随机,质数密度是 \(\frac{1}{\ln n}\),所以我们大概就有 \(\frac{1}{2\ln n}\) 的概率问到我们想要的一个位置,那根据生日悖论那套来讲,其实我们随机一些次数,就有很高的概率成功。现在再来思考我们得到这个位置后要怎么去检验?

假设这个位置是 \(p\),则我们每一次的 \(lcm\) 都含有质因子 \(p\),因此假设我们再用这个位置,随机若干个位置和他结合进行询问,则取 \(\gcd\) 以后肯定是 \(p\) 的倍数;另一方面我们大概率不会出现另外的质因子,因为就算是出现次数最频繁的 \(2\),每次也只有 \(\frac{1}{2}\) 的概率出现,则随机 \(k\) 个位置的话他只有 \(\frac{1}{2^k}\) 的概率会出现。因此我们得到结论:首先这个 \(\gcd\) 极大概率满足不是 \(1\) 就是质数,如果是质数,则我们取最大的(因为可能会出现 \(\le mid\) 的质数也满足这个条件,所以不能任取一个),就找到了一个 \(2p\ge r\) 的质数及其位置。

我们取 \(200\) 个位置,每次随机检验 \(25\) 次即可。

记录

19. 移球游戏

非常高妙的构造,放到现在感觉仍然是 NOIP T3+ 难度,唯一问题是部分分不太好设计。

先来考虑 \(n=2\) 的做法,发现并不是非常一眼。

尝试提炼出一些操作:我们从栈顶向栈底开始标号,则我们可以做到交换两个不同栈的第 \(x\) 和第 \(y\) 个位置,前提是 \(x+y\le m+1\)。具体可以这样实现:把第一个栈第 \(x\) 个以上的,和第二个栈第 \(y\) 个以上的(不包含 \(x\),但包括 \(y\))全部放入额外栈,然后把第一个栈的 \(x\) 放入第二个栈,再把额外栈的栈顶(应该是 \(y\))放入第一个栈。然后栈顶的 \(y-1\) 个人全部属于第二个栈,放回去;然后栈顶余下的 \(x-1\) 个人全部属于第一个栈,放回去。步数大概是 \(2m\) 级别的。

利用这个操作,我们能构造出一种 \(O(m^2)\) 级别的解决 \(n=2\) 的方法:我们试图强制让第一个栈全部是 \(1\)。那么我们从栈底开始向上考虑。如果考虑到编号为 \(i\) 的人的时候他是 \(2\),注意到我们可以和第二个栈里前 \(m-i+1\) 个人里的某一个任意对换。假如这里有一个 \(1\),我们就直接开换完事;否则假设第一个栈里,标号 \(\lt i\) 的位置还有一个 \(1\):我们可以把他和第二个栈的栈顶对换,然后把第二个栈的栈顶和第一个栈的第 \(i\) 个位置对换。我们证明一定能找到这样一个位置:不妨考虑反证,那这个栈里编号 \(\gt i\) 的全是 \(1\)\(\le i\) 的全是 \(2\);也就是有 \(i\)\(2\)\(m-i\)\(1\)。那么另一个栈里就有 \(m-i\)\(2\)\(i\)\(1\)。因此根据抽屉原理从栈顶开始往下,前 \(m-i+1\) 个人里必定有一个 \(1\),而第一个栈里编号为 \(i\) 的位置刚好能和第二个栈的前 \(m-i+1\) 个人对换,因此就证明了我们想要的东西。


此时我们直接把这个思想拓展到一般情况:一个一个栈考虑,当我们把第 \(i\) 个栈全部变成 \(i\) 的时候,就删去他,然后变成一个子问题。

套用 \(n=2\) 的做法:假设考虑到了第 \(i\) 个栈的编号为 \(j\) 的位置,那么我们首先考虑 \(\gt i\) 的栈里编号 \(\le m-j+1\) 的位置是否存在一个 \(i\);如果不存在,则在找 \(=i\) 的栈里 \(\lt j\) 的位置,或者 \(\gt i\) 的栈里任意的位置的一个 \(i\),把他和一个 \(\neq i\) 的栈顶互换,再换到 \((i,j)\)

不难证明操作次数是 \(O(nm^2)\) 级别的,此时我们拿下 \(40\) 分。我想了很久只能做到这里。


我们发现 \(n=2\) 的操作是解决这个问题的关键:如果我们能在更低的次数内解决 \(n=2\) 才有可能完全解决这道题。考虑继续提炼出一些更自然的操作。发现我们可以做到把一个栈的第 \(x\) 个位置提前到栈顶而不改变其余元素的相对顺序:只用这个栈和垃圾栈是不够的,我们需要利用到第二个栈:先把第二个栈拿出一个元素放进垃圾栈,然后把第一个栈的 \(x-1\) 个顶元素放入垃圾栈,然后把第一个栈的第 \(x\) 个元素放入第二个栈,然后把垃圾栈里前 \(x-1\) 个元素放回第一个栈,然后把第二个栈的 \(x\) 元素放回第一个栈,然后把垃圾栈里仅存的那个元素放回第二个栈。这样花费 \(O(m)\) 次操作。

发现我们用这个手法可以做到更强的东西:直接在 \(O(m)\) 次操作内,指定栈中的 \(x\) 个位置,然后把他们全部提前到栈顶,同样改变相对顺序。操作过程类似,只不过要把第二个栈的前 \(x\) 个元素提前压入垃圾栈。

然后我们就能 \(O(m)\) 次解决 \(n=2\) 的情况了:直接 \(O(m)\) 地把两个栈里的 \(1\) 放到顶部,然后两个栈的 \(1\) 全部拿出来放进 \(n+1\),把两个栈的 \(2\) 合并起来放到第二个栈,然后把 \(m\)\(1\) 放回第一个栈。

那是不是我们直接开香槟了?其实也不是:注意到我们不能套用先前归纳的思路,因为我们得每次把 \(\gt i\) 的栈里所有 \(=i\) 的元素提前到栈顶,最坏情况下每个栈里都有至少一个,那我们对每个栈都要 \(O(m)\) 次,次数又变成 \(O(nm^2)\) 了,所以我们得把这个 \(n=2\) 换一种方法使用。

考虑分治:我们类似快速排序,把 \(\le mid\) 的元素看成 \(1\) 放入左半边,\(\gt mid\) 的元素看成 \(1\) 放入右半边。那么我们把每个栈的 \(1\) 先提前到顶部,然后考虑枚举左边的一个栈:假设他还缺 \(a\)\(1\),考虑从右半边贪心凑出 \(a\)\(1\),然后把当前栈的 \(m-a\)\(1\),和 \(a\) 个凑出来的 \(1\) 放入垃圾栈,那么当前栈那 \(a\)\(2\) 就原封不动塞入右半边对应的位置。然后把垃圾栈的 \(m\)\(1\) 再放回去。注意到由于我们是贪心凑的,所以右半边可能会有一个栈还有 \(1\) 没用完,但是此时这些 \(1\) 被压在了中间,所以需要花费 \(O(m)\) 的额外代价再次提前。

这样就有 \(T(n) = 2T(\frac{n}{2})+O(nm)\),显然次数在 \(O(nm\log n)\) 级别,可以轻松通过。

记录

posted on 2023-10-09 22:44  Cry_For_theMoon  阅读(179)  评论(1编辑  收藏  举报