「泛做题解」曾经的 Codeforces 题解汇总

注:此博客写于 2017.9 ~ 2018.2

Codeforces Round #422 (Div. 2)

CF822E。给定长度为 $ n $ 的字符串 $ s $ ,长度为 $ m $ 的字符串 $ t $ ( $ m \leq n $ )。问是否能在 $ s $ 中分割出不超过 $ x $ 段不相交的连续子串,使得不打乱顺序后,能够组成字符串 $ t $ ? $ n \leq 10^5,x \leq 30 $

DP,贪心,HASH+二分求LCP。 注意到一个事实,假设已经匹配到 $ s[i] $ ,那么我们一定要让已匹配的长度尽可能长,又由于 $ x $ 的取值并不大,由此得到状态的定义:定义 $ f[i][j] $ 表示 $ s[1..i] $ 划分为 $ j $ 段后,能在 $ t $ 中匹配的最长前缀。

假设 $ f[i][j]=k $ , $ l $ 为 $ s[i+1..n],t[k+1..m] $ 的 $ LCP $ 。考虑向后转移。

  • 一种是不匹配, $ f[i+1][j]=max(f[i+1][j],f[i][j]) $ 。
  • 一种是匹配, $ f[i+tmp][j+1]=max(f[i+tmp][j+1],f[i][j]+tmp) $ , $ tmp $ 不大于 $ l $ 。

可是,这里的第二种转移是 $ O(n) $ 的,考虑如何优化。注意到,对于 $ tmp \leq l $ , $ i+LCP(i+1,f[i][j]+1)=i+tmp+LCP(i+tmp+1,f[i+tmp][j]+1) $ 。所以从 $ f[i] $ 向后转移一定比从 $ f[tmp] $ 向后转移更优(或是相等,需要划分的段更少)。因此,我们只需要转移到 $ f[i+l][j+1] $ 即可。

$ LCP $ 可以通过后缀数组(窝不会)或者经典的 $ HASH $ +二分求出。

Code

CF 822F。给定一棵树,每个节点有一个秒表,可以选择若干条不相交路径。对于一条路径, $ a1,a2,a3...,ak $ ,选择边 $ (ai,ai+1) $ 上距离 $ ai $ 为 $ x $ 的位置出发。先一直走到 $ ak $ ,然后再返回到 $ a1 $ ,如此往复。每秒钟走一条边。当点到达某个节点时,会把节点的秒表置 $ 0 $ 。请构造一种方案,使得节点 $ 1 $ 秒表的最大值最小,如果相同,使得 $ 2 $ 的最大值最小,以此类推。 $ n \leq 100 $

贪心,构造。题意比较鬼畜,可能比较奇怪?注意到,一定是把所有单独的边作为路径最优。这样所有的运动就是以 $ 2 $ 为周期的。对于节点 $ i $ ,假设它的度为 $ d[i] $ ,我们将时间 $ 2 $ 划分为 $ d[i] $ 段,让 $ d[i] $ 条边上的点以 $ \large \frac 2 {d[i]} $ 为周期访问 $ i $ 。所以说因为这样的最优值唯一,所以和字典序无关。

算法用DFS实现,注意父节点向子节点的传递。

Code

扫描二维码关注公众号,回复: 1539357 查看本文章
Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals)

CF828D。请构造一棵包含 $ n $ 个节点, $ k $ 叶子节点的无根树。使得叶子节点的距离的最大值最小。 $ n \leq 2 \times 10 ^ 5 $

贪心,构造。 以 $ 1 $ 为根,分出 $ k $ 个分支,答案一定是最优的。为什么呢?如果不这么做,达到相同的距离需要的边数会更少,增加边数后,答案一定更劣。三个月前的Cyani好傻逼啊。

Code

CF828F。给定一个连通图,对于每条边求出它的最大权值,使其在图的所有最小生成树上(不改变其他边的权值)。 $ n,m \leq 10^5 $

最小生成树,倍增。 非常套路的题,首先求出MST(也一定是最小瓶颈树),然倍增搞一搞就好了。分为两种情况:

  • 这条边不在MST中。直接倍增求路径的 $ \max $ 。(如果想要更小的常数,可以并查集按秩合并,不过不能修改??)
  • 这条边 $ (u,v) $ 在MST中。取连接 $ u,v $ 两端的非MST边, $ (u,v) $ 一定要比最小值还要小,似乎要枚举每一条边?Cyani好傻逼啊。其实也可以倍增,只是从大的推到小的罢了。

嘴巴上AC很容易啊。既然是嘴巴选手,那么我就先不写。。

UPD: Code

Codeforces Round #427 (Div. 2)

CF835E,交互题。 已知存在 $ n $ 个数,只有两个数是 $ y $ ,其他的数都是 $ x(x\not=y) $ 。您可以询问任意一个子集的 $ xor $ 和。求出 $ y $ 所在的两个位置。询问数不得超过 $ 19 $ 。

构造好题,异或性质利用,二分查找。 非常巧妙的一道题啊,考虑一个问题:如果只存在一个数为 $ x $ ,应该怎么做?很显然只要二分查找,不断缩小范围。关键在于如何区分两个 $ y $ ,

一开始的想法是随一半的位置,直到两个 $ y $ 存在不同的集合之中?应该不超过7,8就好了,很显然会被卡。由于数据组数过多,不能使用概率算法。

假设两个位置分别为 $ a,b $ 。考虑一个难以发现的性质,我们只需要不超过 $ 10 $ 次询问,询问强制某一位为0的子集,确定 $ a,b $ 在这一位是否相同。就能得到 $ a \oplus b $ 的值。然后我们对 $ a $ 进行二分搜索即可。可是,似乎这样仍然需要 $ 20 $ 次?

注意到 $ a,b $ 的顺序是无关对,对于某一位 $ a \oplus b=1 $ (显然一定存在),只要强制 $ a $ 的那一位为 $ 0 $ 就好了。好妙啊。

一个有趣的事实,官方题解说不存在算法能够小于 $ 19 $ 次来解决这个问题(随机乱搞当然不算啊)。为什么呢??题解没说。蒟蒻Cyani来口胡一下:对于每一个询问,实际上只能得到 $ 2 $ 种回复,偶数个或是奇数个 $ 1 $ 。总共的情况数为 $ C(1000,2)<2^{19} $ ,所以说至少 $ 19 $ 次询问才能对应唯一一种情况。

Code

CF835F。给定一个有 $ n $ 个节点和 $ n $ 条边的图,任意两点相互联通,无自环,无重边,求删掉一条边形成的树的直径的最小值。 $ n \leq 2 \times 10 ^ 5 $

环套树,树的直径。 显然是一个环套树,假设环上有 $ k $ 个点。首先假设每个点对应的最大深度为 $ di $ ,断开 $ (i,i+1) $ 。那么有三种情况, $ [1,i] $ 直径最大的点, $ [i+1,k] $ 直径最大的点, $ [1,i] $ 到 $ 1 $ 的最优距离 $ +1 $ 到 $ k $ 的边 $ +[i+1,k] $ 到 $ k $ 的最长距离,取三者的最大值,来更新最小值。显然这些都可以 $ O(n) $ 预处理。

注意外向树的直径!

貌似成为一名嘴巴选手了QAQ,代码周末补吧。。

UPD: Code

2KB代码写了1h,我好弱啊啊啊

自我感觉求基环的部分很简洁,以后就这么写啦。。

Codeforces Round #428 (Div. 2)

CF839D。给定一个集合,包含一些整数 $ ai $ 。一个子集 $ s={a[i1],a[i2],a[i3],...,a[ik]} $ 的力量定义为 $ k\times \gcd{s} $ 。求所有子集的力量总和。 $ n \leq 100000 $

数论,容斥原理。 考虑每个 $ gcd $ 的贡献。定义 $ f[i] $ 为大小为 $ i $ 的集合的所有子集,的大小之和,显然有 $ f[i]=2f[i-1]+2^{i-1} $ 。但是这样会算重,由此想到容斥原理。

假设集合中 $ k $ 的倍数有 $ cnt $ 个, $ f[cnt] $ 可以得到, $ \gcd $ 是 $ k $ 的倍数的贡献。考虑从 $ k $ 从大到小枚举,减去被数的个数,由此可以的得到 $ \gcd = k $ 的个数。

Code

CF839E。给出 $ n(n≤40) $ 个点的邻接矩阵,要求给每个点赋值,使得点的权值和为 $ K $ ,每条边权值为两端点点权的乘积,最大化边的权值和。

最大团问题。 不会做啊,CF的Div2竟然有论文题!!!题解,有时间再补。

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals)

CF831F。有 $ n $ 棵竹子,竹子每天长 $ 1m $ ,每个竹子都有一个临界高度 $ ai $ ,每 $ d $ 天去看竹子,如果有竹子的高度超过了对应的临界高度,就它砍断(不会再长高),然后把高于 $ ai $ 的部分收集起来现在求一个最大的 $ d $ ,满足最后收集到的竹子长度小于等于给定的 $ k $ 。
$ n \leq 100,k \leq 10^{11},ai \leq 10^9 $

数论,分块好题。 假设隔 $ d $ 天看一次竹子,那么得到的长度为:

\[ \large \sum_{i=1}^n \left( d\times \lceil\frac {ai} d \rceil - ai \right)​ \]

又需要满足条件,得到不等数,再两端再同除以 $ d $ ,整理得到,( $ sum $ 表示 $ k $ 与 $ ai $ 之和)

\[ \large \sum_{i=1}^n \lceil \frac { ai } {d} \rceil \leq \lfloor \frac {sum} d \rfloor \]

考虑按照 $ \large \lfloor \frac {sum} {d} \rfloor $ 来分块,如果存在 $ d1,d2(d1<d2) $ 满足:

\[ \large \lfloor \frac {sum} {d1} \rfloor = \lfloor \frac {sum} {d1} \rfloor \]

如果 $ d1 $ 满足,那么 $ d2 $ 一定满足。所以,我们只要对于块内的最大值进行check。复杂度 $ O(n\sqrt{sum}) $ 。

Code

Codeforces Round #426 (Div. 2)

CF834C。有 $ n $ 场游戏,初始分均为1,每回合,胜者分数乘上 $ k^2 $ ,输的分数乘上 $ k $ ,(每一回合的 $ k $ 都是任意的)。给定两个数 $ a,b $ ,问这两个数是否可能是他们最终的分数。 $ n \leq 3.5\times 10^5,a,b \leq 10^9 $

数论,二分。 注意到 $ a\times b $ 一定可以表示为 $ k[1]^3 \times k[2]^3 \times k[3]^3 \times ... \times k[m]^3 $ ,此处的 $ k[1],k[2],... $ 有可能相等。考虑二分找到 $ mid=k[1]\times k[2]\times ... \times k[m] $ ,如果能找到并且 $ mid|a,mid|b $ ,那么一定是存在一种方式的,反之则不存在。

话说Cyani在VP的时候好傻逼啊,竟然不会做。暴力乱搞搞到TLE69,优化无果就弃了。rk:800+

Code

CF834D。有一个长度为 $ n $ 的序列,划分为 $ K $ 个连续子序列,每个子序列的价值为不同的元素种类。求所有子序列的代价总和的最大值。 $ n \leq 35000,K \leq 50 $

DP,线段树。 显然是一个DP,首先考虑最暴力的方式:定义 $ f[i][j][k] $ 表示前 $ i $ 个元素划分为 $ j $ 个子序列,最后一个子序列从 $ k $ 开始。两种转移:

  • 从 $ f[i-1][j][k] $ 转移,如果 $ [k,i-1] $ 中没有出现过 $ a[i] $ ,那么加一。判断是否出现,我们只需要记录每个元素上一次出现的位置即可。
  • 从 $ f[i-1][j-1][t]+1 $ 转移到 $ f[i][j][i] $ 。

发现状态难以优化,考虑优化转移。事实上,我们可以将所有 $ f[i][j][] $ 用线段树维护,对于转移1,就是区间修改,转移2就是询问区间最值。维护 $ K $ 棵线段树即可。

Code

CF834E。给定区间 $ [L,R] $ ,求区间中的数去掉这个数中的 $ 0 $ 之后,把这个数各个数位上的数从小到大排列后,总共有多少个不同的排列情况。 $ L,R \leq 10^{18} $

爆搜。 又是爆搜??暂时弃了。。

Codeforces Round #429 (Div. 2)

CF841D。给定一个包含 $ n $ 个节点, $ m $ 条边的无向图。可能包含重边,但不包含自环。每个节点的值 $ di $ 可能为 $ 0,1,-1 $ 。找出一个边的集合满足:对于每个点 $ i $ ,在集合中 $ i $ 的度数模 $ 2 $ 为 $ di $ ,或者 $ di=-1 $ 。 $ n,m \leq 3\times 10^5 $

构造。 算是比较好的一道构造题。考虑这样一个事实:如果存在解,那么一定存在一个解满足构成的图是森林。为什么?如果存在一个环,那么把所有环的边去掉,节点度的奇偶性仍然不变。于是可以像树一样进行 $ DFS $ ,考虑每一条边是否需要保留即可。

考虑这样一个性质,对于树上的一条路径,只有路径两端的奇偶性才会变化。如果 $ DFS $ 到了节点 $ u $ ,可以通过 $ u $ 将 $ u $ 的子树中的路径配对(如果 $ d[u]=1 $ ,那么 $ u $ 也要配对)。最后只会留下 $ 0,1 $ 条未配对路径,返回给父节点。

Code

CF841E。给定包含 $ n $ 个数的数组 $ a[] $ ,对于一个长度为 $ n $ 的置换 $ P $ ,如果对于 $ 1 \leq i < n $ ,不存在 $ a[p[i]\times a[p[i+1]] $ 是完全平方数,那么置换 $ P $ 是满足条件的。求有多少个置换是满足条件的。 $ n \leq 300 $

组合,DP,好题。 考虑将所有数划分为若干个组,每个组的数两两相乘都是完全平方数(也就是这些数包含的质因子的指数奇偶性相同)。这样就转化为,存在若干种物品,同种物品不能相邻的方案数。设第 $ i $ 组有 $ cnt[i] $ 个数,考虑DP。

定义 $ f[i][j] $ 表示,对于前 $ i $ 组数,存在 $ j $ 对相邻为同组的数的方案,对于同组的数是无序的。于是我们在转移(加入一组新的数)的时候,首先将这组数划分为 $ k $ 段,再挑选 $ p $ 段插入到相邻的同组数中,最后再将剩下的段插入。其中 $ m=cnt[1]+cnt[2]+...+cnt[i-1] $ 。

\[ \large f[i][j+cnt[i]-k-p] = f[i-1][j] \times C(cnt[i]-1,k-1) \times C(j,p) \times C(m-1-j+2,k-p) \]

Code

Codeforces Round #431 (Div. 1)

CF848B。有一个 $ W*H $ 的矩阵在坐标轴上。从 $ x $ 轴出发有一些舞者,在位置 $ pi $ 时间 $ ti $ ,沿着 $ y $ 轴正方向走。 $ y $ 轴同样如此。当两个舞者相遇时,他们会改变各自的方向为对方的方向。问所有舞者的最终位置。
$ W,H,n \leq 10^5 $

脑洞题。注意到满足 $ pi+tj=pj+ti $ 的两个舞者会相遇,可以按照 $ pi-ti $ 的值将所有舞者划分为若干类,每一类都会碰撞一次。根据 $ x,y $ 轴上的舞者数目可以 $ O(1) $ 判断每个舞者交换后对应的舞者。

Bubble Cup X - Finals (Online Mirror)

CF852A。给一个 $ 10^{200000} $ 以内的数字,支持一种操作:在数字之间加若干个加号,把原数字变为加法运算后的结果,要求在三次操作内把数字变成个位数,输出方案。

随机化。 注意到如果每次在所有数字间加上加号,容易出现 $ 999.. $ 的情况。所以可以随机化,每一次多合并相邻的两位,直到答案符合要求。还是比较容易被满足的。

CF853C。给定一个正 $ 2n $ 边形,每条边被分为 $ n $ 等分,其中第 $ 0,2,..,2n-2 $ 条边上各选择一个蓝点 $ B0,B2,..,B2n-2 $ (保证是 $ n $ 的置换)。 您需要确定 $ B1,B3,..,B2n-1 $ (同样是 $ n $ 的置换),使得这些 $ B $ 点构成的面积最大。

贪心,一次函数。 注意到白色三角形的面积总和是关于 $ B1,B3,.. $ 的一次函数。计算出系数后,根据排序不等式即可贪心配对。

Manthan, Codefest 16

CF633E。给定 $ n $ 和长度为 $ n $ 的两个数组 $ v[i],c[i] $ ,定义区间的价值
$ \large p(l,r) = \min(100 \times \max {k=l} ^{r} v[k], \min {k=l} ^{r} c[k]) $
会随机选择一些 $ li $ ,您会选择对应 $ ri(li \leq ri) $ ,使得 $ p(li,ri) $ 最大。求所有最大值的最小值的期望值。
$ n \leq 10^6 $

期望,对数转化。 注意到对于给定的 $ l $ ,我们可以预处理 $ ans[l] $ 为最大的 $ p(l,r) $ 。具体就是 $ ans[i] = \min ( \max (100 \times v[i], ans[i+1]), c[i]) $ 。

发现选择的 $ K $ 个 $ ans[i] $ 中,只有最小的一个才会产生贡献。考虑所有 $ ans[i] $ 按照递增来排序,新的 $ ans[i] $ 的贡献为 $ \large \frac {C(n-i,K-1) \times ans[i]} {C(n,K)} $ 。发现 $ n $ 实在是太大了,所以可以将组合数转化为对数的运算。

Code

CF633D。给定一棵带点权的树,选取两条不相交路径,求点权和最大值。
$ n \leq 10^5 $

树形,背包DP。 一开始我是拆分为三种状态,然后十分复杂的转移,WA23了QAQ。

后来看见一种很简洁的写法。用 $ f[i][j][k] $ 表示, 以 $ i $ 为根的子树中,已经选择了 $ j $ 条路径,当前 未确定的路径,和根向下延伸的条数。转移就变成类似背包的形式。注意一些特殊情况,还要手动完成选择。

Code

#001 2016-2017 ACM-ICPC, NEERC, Moscow Subregional Contest

A,B,F,G,签到。K,克鲁斯卡算法。L,期望,用线段树维护,或者倒着处理。H,模拟。E,DP,输出方案。

I. 交互题。
给定 \(n\) ,系统生成了两个数 \(0 \leq x0 < m \leq n(n \leq 10^{18})\)。 第 \(i\) 次询问,你可以给出一个数\(ai\) 。那么 \(x[i]=(x[i-1]+ai)\%m\) 。系统会返回 \(x[i]\)\(x[i-1]\) 的大小关系。求 \(x0,m\) 的值。不能有超过 \(2016\) 次询问。

交互,倍增。 首先感谢r爷,赐予我神奇的题解Orz。

基本思路: 考虑先搞出 \(m\) ,同时,我们统计累加的 \(a\) 之和,就可以得到 \(x0\) 了。

方便处理,我们用以下一段代码来询问:如果爆出来了,就返回 \(1\)

int ask(LL a) {
    tot2 += a; tot1 += tot2 / MOD; tot2 %= MOD;
    printf("%I64u\n", a); fflush(stdout);
    getchar(); char ch = getchar();
    return ch != '>';
}

关键性质:

  • \(+a\) 爆出去后的值 \(\in [0, a)\)
  • 任意时刻只要 \(a \leq m\) ,就不会套圈,而影响判断。所以我们要一直做到 \(a \leq m\)

具体步骤:

首先搞出一个 \(step\) ,不超过 \(m\) ,但又不至于太小。考虑倍增,依次加 \(2^0,2^1,2^2,...\) 。直到第一次爆出去。然后再依次倍增,直到又爆出去。两个取 \(\max\) ,就会得到 \(m\) 的级别 \(step\)。此时,\(step\) 不会小于四分之一的 \(m\)

s1 = 1; while (!ask(s1)) s1 += s1;
s2 = 1; while (!ask(s2)) s2 += s2;
step = max(s1, s2);

考虑每一次 \(+step\) ,同时令 $ M+= step$ ,直到第一次爆出去。

此时 \(x[i] \in [0,step)\)可以发现 \(x[i]+M-step\) 一定不会爆出去(因为 \(M < m\) ,所以这个值也小于 \(m\) )。

之后 \(step /= 2\) ,就可以逐步缩小 \(x[i]\) 的范围。但是如果是 \(step\) 为一步慢慢跳,显然询问次数会爆炸。所以直接可以跳 \(M-step\) (上面的结论)。

直到 \(step = 1\) ,此时 \(x[i] = 0\) 。那么重新跳一遍就可以得到 \(m\) 的值。

于是代码如下:

while (step) {
    bool flag = 0;
    while (!ask(step)) m += step, flag = 1;
    if (flag) m -= step;
    if (m > 0) ask(m);
    step >>= 1; 
}
while (!ask(1)) m++; m++;
x = (m - (MOD % m * tot1 + tot2) % m) % m;
printf("0 %I64u %I64u\n", x, m);
#002 Bubble Cup 8 - Finals [Online Mirror]

B,D,F,H签到。

A. 定义一个序列 \(F_n\) 。满足 \(F_n=s_{n-1}F_{n-1}+s_{n-2}F_{n-2}, F_0=0, F_1=1\)

其中 \(s\) 是一个近乎循环序列。给定 \(N\) ,同时给出 \(s_0,s_1,s_2,...,s_{n-1}\) ,满足 \(s_i=s_{i \bmod n}\) 。同时存在 \(m\) 个特殊位置,\(si\) 的值是给定的。求 \(F_K \bmod P\) 的值。

线段树维护矩阵。 显然,我们可以预处理 \(s_0,s_1,s_2,...,s_{n-1},s_0\) 构成的转移矩阵 \(S\) 。然后,对于改变的 \(si\) 的值,只会影响两个矩阵。对于每一个周期,会影响的也至多只有 \(2m\) 个,记为 \(E_1,E_2,...,E_t\)

最终的转移矩阵类似于 \(S \cdot S \cdot E_1 \cdot S \cdot ...\cdot E_2\cdot S\cdot...\) 。中间的可以利用快速幂,时间复杂度 \(O(m \log K)\) 。考虑如何计算 \(E_i\) ,显然我们需要计算一段矩阵的乘积,线段树维护即可。

总的复杂度 \(O(m \log K + m \log K)\)

C. 爆搜+匈牙利算法。直接这样是 \(O(\binom n {n/2} n^3)\) 的,可以减少一个 \(n\) 。未理解。

E.最大 的一个圆,能够覆盖所有斜放的正方形(都是整点)。要求这个圆经过三个顶点。求这三个顶点。

计算几何。 一眼看 最小 圆覆盖,于是跑去学算法,想法还是很高明哒。。套在这题当然是萎的。。(你怎么又看错题了。。

考虑首先求出凸包。然后选择的三个点一定是凸包上相邻的,否则显然有更优的方案来代替。

然后求外心,就,,没了。。。

F. 存在 \(O(n)\) 的贪心做法。维护当前答案的可行区间。

G. 给定一个带权无向图,每条边的代价为边权/当前速度,每次到达一个新节点,速度都会除以\(10\) 。求 \(1\) 号点到 \(n\) 号点的最小代价,如果多解输出点数最少的解,输出代价、路径点数、路径经过的点。\(1 \leq n,m \leq 10^5, 0 \leq w \leq 9\)

基数排序,贪心,BFS。 首先,如果存在到终点距离为 \(0\) 的点,可以额外处理。否则选越短的路径越好,而路程的距离相当于边的权值构成的十进制数,我们考虑从高位贪心。

具体可以预处理出到起始点的距离,按照层来处理,再基数排序。

I. 有一个正方形区域,要求支持两个操作:1、放置等腰直角三角形,给定放置方向(有4个方向,直角边与坐标轴平行),直角顶点坐标,边长。2、查询一个点被覆盖了多少次。

\(1 \leq n \leq 5000,1 \leq Q \leq 10^5\)

树状数组,坐标转换。

#003-8VC Venture Cup 2017

A,B,C签到。E高精度+DP,F代码题。

D. 考虑这道题的一个性质,每一个单独的元素看成一个区间。每一次操作就相当于移动左边界或者右边界。
很重要的一个性质就是:相对位置不变,只是长度改变。考虑预处理 \(Next[i][j]\) 数组。表示从第 \(i\) 个位置开始的下一个 \(j\) 的位置。然后DP,\(f[i][j]\) 表示填充了前 \(i\) 个位置,最后一个位置是原来的第 \(j\) 个元素。然后枚举下一个字母 \(k\) 转移即可。

考虑优化,我们搞一个辅助数组 \(g[]\)\(sum\)\(sum\) 用来动态维护答案,\(g[s[j]]\) 用于保存当前以 \(s[j]\) 结尾的 \(g[i][j]\) 。每一次循环的时候,\(sum = sum + f[i-1][j] - g[s[j]-'a']\), 同时令 \(g[s[j]-'a'] = f[i-1][j]\)。表示之后如果通过 \(s[j]-\)a 来转移,就要从新的位置转移过来。

#004-Codeforces Round #372 (Div. 1)

A签到。C点分治,E奇怪的图论+DP+FFT?

B. 给定一个带权无向图,有若干条边权未知,构造出一种方案使得最短路为 \(L\)

考虑首先令每一条未确定边的边权为 \(1\) ,跑一遍Dij,如果最短路不小于 \(L\) ,显然没救了。

假设当前最短路与 \(L\) 相差 \(need\) 。考虑再一次跑Dij,需要令 \(dist2[u]\) 尽可能等于 \(dist1[u]+need\) (每次更新时,如果能放大,就尽量放大)。最后检查 \(dist2[t]\) 是否满足要求即可。

D. 需要你构造一个 \(n \times m\) 的方格,每条边都可以设置障碍,只能向右/下走,使得从 \((1,1)\)\((n,m)\) 的方案数为 \(T\)

按照进制分解,逐步构造。 题解

一些算法

数论

CF222C 给出两个集合,第一个集合数的乘积是分子,第二个集合的数的乘积是分母,要求够造一个同样大小的集合,但是得到的分数是化简过的。\(1≤n,m≤10^5,ai,bi \leq 10^7\)

质因数分解,构造。考虑首先筛出\(10^7\)内的所有素数,然后对所有数质因数分解。最后暴力消除即可。为了保证一定能存在答案,只需要在原来数的基础上消除即可。

CF446C 给定\(n\)个元素的数组\(a[]\)。操作\(1, l, r\)。要求对于\(l \leq i \leq r\)\(a[i] += f[i-l+1]\)。询问\(2,l,r\)。返回\(\sum_{i=l}^{r} a[i]\),对\(10^9+9\)取模。其中\(f[i]\)为斐波那契数列,\(f[1]=1,f[2]=1\)\(n,m \leq 300000\)

斐波那契数列,线段树维护等比数列。本题似乎无从下手,因为每一个数增加的值不同。事实上,我们可以利用斐波那契数列的的通项公式(可以用母函数证明,是线性常系数其次递推关系,可窝不会)。

\[ \large fib(i) = \frac {1} {\sqrt{5}} \left( \left(\frac {1+\sqrt{5}} {2}\right)^n + \left( \frac {1-\sqrt{5}} {2} \right)^n \right) \]

\(\large q1= \frac {1+\sqrt{5}} {2}, q2 = \frac {1-\sqrt{5}} {2}\),于是我们只需要维护两个等比数列即可,由于公比是 \(q1,q2\) 不变,所以直接利用等比数列求和即可,用线段树维护区间和。注意,本题需要得到 \(q1,q2\) 在模意义下的值,只需要暴力算出 \(\sqrt5\) 即可。

顺便提一下,我们需要利用等比数列求和公式 \(\large \frac {q^n-1} {q-1}\) ,但是本题中 \(q1,q2\) 满足 \(q^2-q-1=0\),就是说 \(rev(q-1)=q\),原来的公式就变为了 \(q^{n+1}-q\),足以见得斐波那契数列的神奇。

CF711E,2A。给定 \(n,k\),已知一年有 \(2^n\) 天,选取 \(k\) 个人,两个人的生日是在同一天的的概率。要求答案写成最简分数。\(n,k \leq 10^{18}\)

欧拉定理降幂,组合相关。首先需要特判一个情况,就是 \(k>2^n\) 概率就是 \(1\)。从反面情况入手,总共生日的方案数为 \(A=2^{nk}\),所有人的生日互不相同的情况为 \(B=A_{2^n}^{k}\)。答案即为 \(\large \frac {A-B} A\) 。注意到,\(A\) 的质因数仅有 \(2\),所以我们需要知道\(B\)中质因数\(2\)的个数即可。考虑其展开式,

\[ \large B = A_{2^n}^k = 2^n \times (2^n-1) \times (2^n-2) \times ... \times (2^n-k+1) \]

首先,\(2^n\) 中有 \(n\) 个,然后若存在 \(2^n-a2^b(b<n)\) ,那么显然这一项含有 \(b\) 个质因数\(2\),所以我们只要统计 \((k-1)!\) 的质因数 \(2\) 的个数即可。

但是 \(A=2^{nk}\),指数过大,应该如何处理。考虑降幂大法,欧拉定理:

\[ \large a^{\varphi(m)}\equiv a^{0} \pmod m \]

所以指数对 \(\varphi(m)\) 取模即可

CF121C,1A。对于一个数,如果它仅包含 \(4\)\(7\),则称之为幸运数。求 \([1,n]\) 的第 \(K\) 个置换,有多少幸运数位于的位置也是幸运数。\(n,k \leq 10^9\)

观察,求第\(K\)排列。注意到 \(k\) 很小,当 \(n>=14\) 时,最前面的 \(n-13\) 位是不发生改变的。而且 \(10^9\) 内的幸运数只有 \(1023\) 个,所以,对于前面的数字,我们暴力计算,后面的,暴力求出第\(K\)排列即可。

CF772C,1A。给定 \(m\)\(n\) 个整数 \(ai(0 \leq ai \leq m-1)\),请您构造一个最长的序列,满足对于所有前缀积对 \(m\) 取模,它们互不相同,且不等于任意一个\(ai\)\(n,m \leq 200,000\)

GCD,DAG最长路。考虑最后一个数与 \(m\)\(\gcd\ t\),可以注意到,这个数通过乘与\(m\) 互质的数,可以得到任意一个与 \(m\)\(\gcd\)\(t\)同样我们也可以乘上一个与 \(m\) 不互质的数,得到与 \(m\)\(\gcd\)\(kt\) 的数。DP得到最长路后,dfs输出答案即可。

考虑证明这一点。其中\(kax \equiv bcx \pmod m\)\(x\) 是原来最后一个数与 $m $的 \(gcd\)(所以 \(a\)\(m\) 互质),\(cx\) 是新的 \(gcd\),由乘上一个 \(k\) 得到。然后 \(ka \equiv bc \pmod {\frac m x}\) ,因为 \(a\)\(m\) 互质,所以一定存在 \(k\)

CF396B,1A。定义函数 \(v(n)\) 为不大于 \(n\) 的最大素数。定义函数 \(u(n)\) 为大于 \(n\) 的最小素数。求 \(\large \sum \frac 1 {v(i) \times u(i)}(2 \leq i \leq n)\)\(T \leq 500,n \leq 1e9\)

裂项,素数判断。思路很巧妙,考虑到,

\[ (u(n)-v(n)) \times \frac 1 {v(n) \times u(n)} = \frac 1 {v(n)} - \frac 1{u(n)} \]

所以我们就可以裂项相消了,于是,

\[ Ans = 1/2 -1/3 + 1/3 - 1/5 + ........ -1/v + \frac 1 {v\times u\times (n-v+1)} \]

消掉,约分即可。

CF283D。对于 \((x,y)\) ,如果满足 \(x\) 可以表示为连续 \(y\) 个整数之和,则它是酷的。如果\((a1,a2),(a2,a3),..,(an-1,an)\) 都是酷的。那么整个序列就是酷的。给定长度为 \(n\) 的序列,求最少改变几个数字,使得整个序列是酷的。\(n \leq 5000\)

数论,动态规划。首先考虑 \((x,y)\) 符合要求的条件,根据等差数列求和公式,可以知道:当 \(y\) 为奇数时,只要 \(x\)\(y\) 的倍数;当 \(y\) 为偶数时,只要 \(2x\)\(y\) 的奇数倍即可。观察第二个条件,也就是说 \(x\) 质因数 \(2\) 的个数比 \(y\) 质因数 \(2\) 的个数少 \(1\),对于其它部分 \(x'\)\(y'\) 的倍数。受此启发考虑令 \(a[i]=2^{x[i]}\times y[i]\),以方便状态的转移。

定义 $ f[i] $ 表示 $ i $ 是不变的,以 $ i $ 结尾的序列,需要满足条件,可以不改变的最长子序列。于是对于一个状态 $ i $ 我们寻找 $ j $ 同样是不改变的。

  • 如果 $ a[i] $ 是奇数( $ x[i]=0 $ ),且 $ y[j] \bmod y[i] = 0 $ ,则 $ f[i] $ 可以由 $ f[j] $ 转移过来
  • 如果 $ x[i]!=0 $ ,条件就比较复杂。首先 $ y[j] \bmod y[i] = 0 $ 是一个必要条件,接下来考虑 $ x[i] $ 与 $ x[j] $
  • 考虑 $ x[i] $ 向前移动,如果向前移动一位,则 $ x $ 必定会减一,于是会出现两种情形。
  • 一是 $ x $ 还没有到 $ j $ 已经变为了 $ 0 $ (也就是 $ x[i]<i-j $ ),变为了奇数,一定能够在最后一次变为 $ x[i] $ 。
  • 二是 $ x $ 到 $ j $ 时仍然不是 $ 0 $ ,这就要求 $ x=x[j] $ ,也就是说 $ x[i]-x[j]=i-j $ 。

至此,问题得到完整的解决。注意一点,我们可以在序列的最后增加一个数 $ 1 $ 使得之前所有状态的答案会聚到这一状态。

CF172D。给定 $ a,n $ ,求 $ [a,a+n-1] $ 所有数的贡献总和。一个数的贡献是其除掉所有平方因子后的部分。 $ n \leq 10^7 $

莫比乌斯函数。考虑求出 $ [1,x] $ 的贡献,考虑首先 $ O(\sqrt x) $ 枚举所有平方因子 $ p^2 $ 。于是我们就需要知道 $ [1,\frac x {p^2}] $ 中不是完全平方数的倍数的数之和,于是可以 $ O(\sqrt {\frac x {p^2}}) $ 的容斥求出答案,容斥的系数就是莫比乌斯函数。复杂度 $ O(n) $ 。

CF451E。有 $ n $ 种颜色的❀,第 $ i $ 种❀有 $ fi $ 朵。求选出 $ s $ 朵❀的不同方案。 $ n \leq 20,s \leq 10^{14},fi \leq 10^{12} $

容斥原理,卢卡斯定理。考虑如果有 $ a $ 种颜色,选 $ b $ 朵,那么方案数就是 $ C(a+b-1,b) $ 。但是本题中❀数量的限制,所以考虑容斥。答案即为至少0个超过-至少1个超过+至少2个超过-...。

比如至少1个超过的是 $ i $ ,那么我们强制选择 $ i $ 所有的❀。组合数的计算可以利用卢卡斯定理。

CF448E。给出一个 $ x,k $ ,每次操作都会将 $ x $ 分解因数,得到新的序列,然后每次再分解序列中的每一个数,按照每一个数分解因数从小到大排,整体顺序不做调整。 $ x \leq 10^{12}, k \leq 10^{18} $

DFS+剪枝。为了加速分解,我们可以预处理 $ x $ 的所有因数。DFS(x,k)表示将 $ x $ 分解 $ k $ 次,只要枚举 $ x $ 的因数,如果可以整除继续DFS,如果超过 $ x $ 直接跳出。加了这个优化以后就很快了。

CF216E。给定一个进制 $ k $ 和一位数 $ b $ 。以及长度为 $ n $ 的序列(均小于 $ k $ )求这个序列存在多少子序列,能通过变换变为 $ b $ ?这里的变换指的是,每次将k进制数x的每一位相加(k进制加法)得到一个新的数 $ x' $ ,直到最后得到一个一位数。 $ 0 \leq b<k \leq 1e9, n \leq 100000 $

$ k $ 进制下模 $ k-1 $ 的性质。注意到一个性质:对于一个 $ k $ 进之下的数,模 $ k-1 $ 后的余数等于,各个数码之和模 $ k-1 $ 的余数。考虑用 $ ans[i] $ 表示前 $ i $ 个数之和模 $ k-1 $ 后的余数,若满足 $ ans[i]-ans[j-1] $ 模 $ k-1=b $ 则 $ [j,i] $ 是符合答案的,于是在扫描过程中记录一个数组 $ cnt[i] $ 表示 $ ans[j] \mod k-1=i $ 的 $ j $ 的个数。注意特殊处理 $ b=0,k-1 $ 的情况。

CF703E。给定 $ n,k $ ,和 $ n $ 个数 $ a[] $ 。求任意一个最短的序列 $ {i} $ 满足 $ a[i1]\times a[i2] \times ... \times a[im] $ 是 $ k $ 的倍数。输出方案,当存在多种方案时,选择 $ \sum i $ 最小的序列。 $ n \leq 1000,k \leq 10^{12} $ 。

GCD,动态规划。考虑到对于一个 $ 10^{12} $ 数量级的数,其因数个数不超过 $ 10^4 $ ,而且本题中 $ a[] $ 是否满足条件是其乘积与 $ k $ 的GCD决定的。首先,预处理出所有 $ k $ 的因数 $ d[] $ ,定义状态 $ f[i][j] $ 表示前 $ i $ 个数中,乘积与 $ k $ 的GCD为 $ d[j] $ 所需要选择的最少数字。按照 $ i+1 $ 是否选择转移即可。

组合数学

CF57C。给定 $ n $ ,求存在多少长度为 $ n $ 的序列满足:所有数在 $ 1 $ 到 $ n $ 之间,这个序列是非递增非递减的。 $ n \leq 100000 $

组合数的格路模型。不失一般性,我们考虑序列是非递减的方案数。可以注意到,假设最后一个数字是 $ n $ ,其等价于从 $ (0,0) $ 走到 $ (n-1,n-1) $ 的方案数。为什么呢?我们可以把向右走看作是到下一个数,向上走可以看成是当前位置的数 $ +1 $ ,并且,序列的数是非递增的。最后一个数可以是 $ [1,n] $ ,同理求出。

CF689E。给定 $ n $ 和 $ K $ ,然后给定 $ n $ 个区间,在 $ n $ 个区间中选择 $ K $ 个,求它们的交集总和。 $ n \leq 100000 $

离散化,贡献。本题似乎难以直接穷举所有的情况,考虑离散化,并计算每一条线段被多少个区间覆盖。假设某一段被 $ x $ 条线段覆盖,那么,我们只需要从这 $ x $ 条中选取 $ K $ 个,就会对答案产生贡献。即为 $ len \times C_{x} ^{K} $ 。

CF28C。有 $ n $ 个人等概率随机进入 $ m $ 个房间,一个房间可以有多个人,第 $ i $ 个房间有 $ ai $ 个水龙头,在一个房间的人要去排队装水,他们会使得最长的队尽可能小,求所有房间中最长队列长度的期望。 $ n,m \leq 50 $

概率,动态规划。注意到,一个房间内原来有多少人到达最长是无法记录在状态中的,所以直接求概率十分困难。考虑概率的原始定义:方案数除以总方案数。也就是说我们求出状态的方案数即可。

用 $ f(i,j,l) $ 表示已经分配了前 $ i $ 个房间和 $ j $ 个人,最长队列长度为 $ l $ 的方案数。首先 $ f(i,0,0)=1 $ 。

状态可以有两种决策转移,一种是当前房间队列到达 $ l $ ,前面的房间任意;另一种是前面有房间队列到达 $ l $ ,但当前的房间任意,于是,

\[ \large f(i,j,l) = \sum _{k=0} ^{l} \left( ^{n-j+p} _{\ \ \ \ p} \right) f(i-1,j-p,k) \\ \large + \sum _{k=0} ^{\min p -1} \left( ^{n-j+k} _{\ \ \ \ \ k} \right) f(i-1,j-k,l) \]

其中 $ p $ 为使得第 $ i $ 个房间队列长度为 $ l $ 的数的集合,需要枚举。

CF15E。给定一个整数 $ N $ ,当 $ N=12 $ 的时候是这样一幅图:

CF15E2

然后你要从最上面的 $ H $ 点出发,走一条道路,这条道路中间不包括任何灰色三角形,最后回到 $ H $ 。 $ N $ 是偶数, $ n \leq 10^6 $ ,问有多少情况,答案对 $ 1e9+9 $ 取模。

递推。为了方便起见,我们以下图所示的阶段划分。

CF15E

由于整个图是对称的,所以我们考虑左半部分。除去几种特殊情况,我们都需要从绿点出发回到紫点,方案数记为 $ g[1] $ 。令 $ f[i] $ 表示陷进去 $ i $ 层的方案数(强制不能从洞口经过,防止重复计数)。令 $ g[i] $ 表示第i个蓝点到红点的方案数,于是显然有,

\[ \large f[0] = 0,\ f[1] = 4,\ f[i] = 4 + 2 \times f[i-1] \]

通过 $ f[] $ 我们可以很容易地递推出 $ g[] $ 。首先,

\[ \large g[n/2] = 1 \]

$ g[i] $ 可以从哪些方面转移呢,第一种是从蓝点 $ i $ 不经过蓝点 $ i+1 $ 回到红点 $ i $ ,根据是否进入洞穴来分;第二种是经过了蓝点 $ i+1 $ 。综上,即为,

\[ \large g[i] = 3 \times f[i-1] + 4 + g[i+1] \times (f[i-1]+1) \]

如何根据 $ g[1] $ 来计算答案?可以注意到,一种是从绿点到紫点再到绿点;一种是从绿点到紫点再直接回去;还有 $ 2 $ 种情况是不经过绿点。于是答案即为:

\[ \large ans = 2 \times (g[1] \times g[1] + 2 \times g[1] + 2) \]

CF40E。给出一个 $ n\times m $ 的矩阵,每个元素都是 $ 1 $ 或 $ −1 $ ,其中有 $ k $ 个位置元素已经确定,并且这个矩阵满足每一行、每一列元素的乘积都是 $ −1 $ ,问有多少种不同的矩阵。 $ 1≤n,m≤1000,0≤k<\max(n,m)。 $

组合,观察。注意到乘积为 $ -1 $ 的等价条件为** $ -1 $ 有奇数个。需要注意一个条件 $ k<\max(n,m) $ ,这意味至少存在一行(或列)是空的**。这是极其重要的一条性质。

假设空的一行为 $ x $ ,我们可以先去填上其他行。此后满足其他行的乘积都为 $ -1 $ ,这个可以通过组合数很容易地算出来。然后,我们要求列的乘积也是 $ -1 $ ,不难发现,第 $ x $ 的每一个数都是唯一确定的。也就是是说,其他行方案的乘积就是总的方案数。

但是这样还没有完,我们仍需要保证第 $ x $ 行的乘积是负数,如何确定呢。注意到,所有数的乘积是 $ (-1)^m $ ,如果 $ (-1)^m \not= (-1)^n $ 则一定无解,否则第 $ x $ 行的乘积一定是负数。

CF830D。给定 $ n $ ,现有深度为 $ n $ 的满二叉树,对于一个节点,给它与它的所有父亲连一条边。 问得到的新的图有多少条不同的简单路径(1->2和2->1算不同路径) 。 $ n≤400 $

树形DP,巧妙非常规的状态定义。首先考虑一个错误的算法通过对错误的分析,可以得到正确的算法。

假设状态 $ f[i] $ 表示深度为 $ i $ 的满二叉树,方案的个数为 $ f[i] $ 。我们考虑按照是否通过根结点来讨论。一种是根经过根据所在子树不同,有 $ f[i-1] \times f[i-1] \times 4 $ 种情况,一种是从根出发或结束,有 $ f[i-1] \times 4 $ 种情况,还有一种是不经过根 $ f[i-1] \times 2 $ ,当然,只包含 $ 1 $ 的简单路径也算,就是要 $ +1 $ 。

可以发现,这比答案大很多。问题出在哪里呢?可以发现,如果我从左子树到根再到左子树,就会发生方案不合法,同时注意到 $ n $ 比较小,考虑附加一些状态来避免非法。

我们需要在同一个子树中选择两个不相交的路径,然后与根相连。此后不相交的路径条数会不变或减小。

这就启发我们还要记录一个状态:此时树中有多少个不相交路径。即 $ f[i,j] $ 表示从深度为 $ i $ 的树中,选出 $ j $ 条不相交的路径的方案数。那么答案就是 $ f[k,1] $ ,按照根所在路径,枚举 $ f[i-1,j] $ 和 $ f[i-1,k] $ 转移如下:

  • 如果让根成为单独的一条路径,那么 $ f[i,j+k+1] += f[i−1,j] × f[i−1,k] $
  • 如果不选根,那么 $ f[i,j+k] += f[i−1,j] × f[i−1,k] $
  • 让根与左儿子中的一条路径结合或和右儿子中的一条路径结合,那么 $ f[i,j+k] += f[i−1,j] × f[i−1,k] × 2 × (j+k) $
  • 从 $ j+k $ 条边中选出两条,让这两条边与根结合形成新的一条边,那么 $ f[i,j+k−1] += f[i−1,j] × f[i−1,k] × C(j+k, 2) × 2 $

真的是一道DP神题!

数据结构

CF538F。现在有一个长度为 $ n $ 的数组 $ a1, a2, ..., an $ 。然后对于 $ k $ 从 $ 1 $ 到 $ n-1 $ 别对该数组建 $ k $ 叉堆。现在要统计对于每一个 $ k $ 叉堆,里面有多少结点是不满足最小堆的性质的。即值比父亲的要小的结点有多少个。他的 $ k $ 个儿子编号是 $ k(v − 1) + 2, ..., kv + 1 $ 。

** $ k $ 叉堆的性质,调和级数,树状数组。注意到一个性质 $ k $ 叉堆的父亲只有 $ n/k $ **,也就是说父亲的总数不会超过 $ O(n(1+1/2+1/3+...+1/n))=O(n\log n) $ 。这就成为了本题的突破口。

考虑从小到大加入每一个数到树状数组,可以枚举这个点作为 $ k $ 叉堆的父亲。由于属于它的儿子一定是一个区间,所以我们可以用树状数组在 $ O(\log ) $ 的时间内统计出贡献。总的复杂度为 $ O(n \log^2 n) $ 。

CF101B。给定 $ n,m $ 。需要从 $ 0 $ 到 $ n $ ,有 $ m $ 种公交车。第 $ i $ 辆公交车从 $ si $ 走到 $ ti $ (可以在中途上车),问有多少种方案可以选择。注意人只能坐车,不可以走。 $ m \leq 100000 $

动态规划,树状数组。首先离散化,按 $ t $ 来排序,我们可以 $ DP $ 。注意到可以转移的状态是一段区间,所以直接用树状数组即可。

CF677D。给定一个 $ n\times m $ 的地图,标有数字 $ [1,p] $ 。需要从 $ 1 $ 出发,依次经过一个 $ 2,3,4... $ 直到 $ p $ 。求最少所需要的步数。 $ n,m \leq 300 $

二维树状数组。考虑从数字 $ k-1 $ 走到 $ k $ 的转移。存在四种转移的方向,以从左上角转移为例。于是转移方程即为 $ f[i][j]=f[x][y]+i-x+j-y $ ,可以拆开使得与 $ i,j $ 无关。 $ f[x][y]-x-y $ 于是把这个东西放在树状数组里,询问二维前缀最小值即可。细节较多,代码较长QAQ

CF372C。有 $ n $ 个点, $ m $ 个烟花要放。给定放的地点 $ a[i] $ 、时间 $ t[i] $ ,如果你当时在 $ x $ ,那么可以获得 $ b[i]-|a[i]-x| $ 的高兴值。每个单位时间可以移动不超过 $ d $ ,初始位置是任意的,求通过移动能获取到的最大的值。 $ $ n \leq 150000, m \leq 300 $ $

DP+单调队列。设 $ f[i][j] $ 表示在放第 $ i $ 个烟花的时候,站在位置 $ j $ 能得到的最多的高兴值。于是有状态转移方程: $ f[i][j]=\max(f[i-1][k])+b[i]-|a[i]-j| $ ,其中, $ \max(1,j-td)<=k<=\min(n,j+td)(t是两次烟花的时间差) $ 。这个复杂度是 $ O(n^2m) $ 。

考虑优化,发现每一次转移的 $ k $ 都是一个区间,于是我们可以用单调队列维护。注意使用滚动数组。

CF827C。给定一个只包含 $ A,T,C,G $ 的字符串 $ S $ ,有如下两种操作。1) $  x,c $ ,修改第 $ x $ 个字母为 $ c $ 。2) $  l,r $ ,字符串 $ e $ ,生成一个由 $ e $ 重复组成的新串,像 $ eee... $ ,问 $ [L,R] $ 中有几个字母跟这个新的字符串对? $ |S|,Q \leq 100000,|e|<=10 $

树状数组,剩余类。考虑对 $ S $ 为 $ 4 $ 个字符,分别建立 $ 10\times 10 $ 的树状数组。表示第 $ i $ 个字符在位置 $ x $ 满足 $ x%j=k $ 的个数之和。看上去很暴力,对吧?接下来分析复杂度。对于一个修改操作,我们需要修改在 $ O(|e|) $ 个树状数组中的值,每次修改的代价为 $ O(\log n) $ 。对于一个询问操作,我们需要询问 $ O(|e|) $ 询问的代价为 $ O(\log n) $ 。所以总体的复杂度为 $ O(Q\times \log |S| \times |e|) $ 。

树相关

CF543D。输入给出 $ N $ 和一些边的关系 $ (p2,p3,p4,…,pn) $ 表示 $ i $ 和 $ pi $ 有连边。对于以任意 $ i $ 为根时,把树边黑白染色,使得任意点走到根的路径上不超过一条黑边,输出染色的方案数。 $ n \leq 200000 $

树形DP,DFS转移。考虑以 $ 1 $ 为根的情况,定义 $ f[i] $ 表示以 $ i $ 为根的方案数,于是有 $ f[i] = \prod (f[j]+1) $ 。

那么,如何将答案转移到子节点上呢?假设 $ u $ 的祖先(非子树)的方案为 $ x $ ,需要转移到 $ u $ 的子节点 $ v $ 。假设 $ u $ 到 $ v $ 的边的颜色为黑色,显然只有一种;为白色时,有 $ \large \frac {x \times f[u]} {f[v]+1} $ 种方案。两者之和作为新的 $ x' $ 转移到子节点即可。每个节点的答案为 $ x \times f[u] $ 。

值得注意的是,由于涉及到除法和取余,所以需要我们计算逆元。但是,特别的,如果 $ f[v]+1=MOD $ ,则不存在逆元,所以需要我们暴力重新计算。

CF396C。给定以 $ 1 $ 为根的树,从节点 $ 2 $ 开始给出每个节点的父节点。 $ m $ 次操作,操作分为两种, $ 1  u, x, k $ ,表示在以 $ u $ 为根的子树上,对于所有其它与 $ u $ 节点的距离为 $ i $ 的点 $ v $ ,加上 $ x-i\times k $ 。 $ 2 v $ ,查询节点 $ v $ 值。 $ n,m \leq 300000 $

DFS序,树状数组。从 $ x-i\times k $ 这个式子入手,显然 $ x $ 可以用DFS序来维护,那么如何处理后一个数字呢?考虑拆开: $ x-i \times k = x - (d[v] - d[u]) \times k = (x + d[u] \times k) + d[v] \times k $ 。可以发现,我们将答案分为了两部分,一部分与 $ v $ 的深度无关,可以用树状数组维护。另一部分与 $ v $ 的深度有关,于是维护 $ k $ 之和即可。区间修改可以差分化,然后用树状数组维护。

CF696B。给定一棵以 $ 1 $ 为根的树,在时刻 $ 1,2,3... $ 访问节点。一开始在 $ 1 $ ,之后以随机的方式 $ DFS $ (保证不重复访问)求对于每个节点,访问它的期望时间。 $ n \leq 100000 $

期望的线性性,树形DP。假设一个节点 $ u $ 已经知道访问父节点 $ fa $ 的期望时间 $ ans[fa] $ ,那么这个节点 $ u $ 的期望时间为多少?考虑到, $ u $ 的兄弟节点各有 $ 50% $ 在 $ u $ 的前面访问,而且需要的代价为整颗子树的 $ size $ 。由此我们可以得到在子树 $ fa $ 访问 $ u $ 的期望时间。再根据期望的线性性,于是,

\[ \large ans[u]=ans[fa] + 0.5 \times (size[fa] - size[u] - 1) + 1 \]

图论

CF208C。给定一个有 $ n $ 个节点的无向图。选一个点成为特殊点,与特殊点相连的边称之为特殊边。求,对于所有 $ 1 \rightarrow n $ 的最短路,经过的特殊边数量的平均值,的最大值。 $ n \leq 100, m \leq n(n-1)/2 $

最短路,拓扑图的DP。考虑到有两种情况,一种是 $ 1 $ 或 $ n $ 成为了特殊点,此时答案一定为 $ 1 $ 。否则我们可以求出经过每个点的最短路条数,即可。在BFS之后,按照距离来排序就完成了拓扑排序。

CF154C。有编号为 $ [1,n] $ 的 $ n $ 个人,并给一些相识关系。对于两个人 $ (i, j) $ 有,对所有剩下的人, $ k $ 要么与 $ i,j $ 相识, $ k $ 要么与 $ i,j $ 不相识,求这样的 $ (i,j) $ 有多少对。

图上的HASH。考虑到我们可以将点连出去的边进行 $ Hash $ ,如果两个点的 $ Hash $ 值相同,则这一对点满足条件。还存在着一个问题,就是说,如果 $ (i,j) $ 本身存在连边,他们的 $ Hash $ 值不同,于是它们可以把自己加入各自的 $ Hash $ 。由于这个 $ Hash $ 函数要求与顺序无关,所以我们可以对每个点赋予一个值,然后加起来或者异或,即可。

CF825E。给定一个有 $ n $ 个节点的 $ DAG $ 。所有的点权是一个 $ [1,n] $ 的置换,如果存在 $ u \rightarrow v $ 的一条有向边,需要满足 $ u $ 的点权比 $ v $ 的点权小。求这个置换,要求最小字典序最小。

贪心,堆,拓扑排序。显然需要贪心,我们有如下两种贪心策略:

  • 按照原图进行拓扑排序,每一次将位置最靠前的赋值为最小值。
  • 按照原图的反图进行拓扑排序,每一次将位置靠最后的赋值为最大值。

哪一种贪心是正确的呢?考虑第一种贪心,不难发现,如果位置最靠前的没有赋值为最小值,对答案或许不造成影响。考虑第二种贪心,如果位置最靠后的没有赋值为最大值,也就是最大值不是在位置最后的点,导致答案的字典序更大。于是用一个堆维护最靠后的位置即可。

动态规划

CF67D。两条直线,各有 $ n(1≤n≤10^6) $ 个点,每个上面的点会和下面的一个点相连,构成一条线段,共 $ n $ 条线段,问这 $ n $ 条线段中,最多有多少线段,它们两两相交?

最长上升子序列。考虑两两相交的条件,对于第一行一些点 $ (a,b,c,..) $ ,如果它们的线段互相相交,则在第二行一定是以 $ (..,c,d,a) $ 的顺序出现。将第二行倒序,就变成了裸的LIS问题。

CF398B。给出 $ n $ 和 $ m $ ,在一个 $ n\times n $ 的平面上有 $ n\times n $ 个瓷砖,其中有 $ m $ 块已经涂色。现在随机选中一块进行涂色(如果已经涂色跳过,也消耗时间),消耗 $ 1 $ 个时间。终止条件为每行每列都有至少有一块瓷砖被涂色。问说涂成满意的情况需要时间的期望。 $ n \leq 2000 $

期望DP。定义状态 $ f[i][j] $ 表示剩余 $ i $ 行和 $ j $ 列没有涂色,直到满足条件的期望时间。划分为四类转移即可。

CF762D。你有一个 $ 3\times n $ 的格子,每个格子都有权值,问从 $ (1,1) $ 出发,到 $ (3,n) $ ,路上经过的权值最大是多少。

巧妙的状态转移。注意到一个性质,一定是在中间一行往回走的。类似与 $ S $ 形的路线。同时可以知道,一定至多往回走一次,因为往回走多次都可以等效地代替。

考虑 $ f[i][j] $ 表示走到第 $ i $ 行第 $ j $ 列时,权值的最大值。于是从 $ f[i][j] $ 可以转移到 $ f[k][j] $ ,只要加上经过的若干个权值。同样的,如果我们往回走一次,可以从 $ f[1][j] $ 转移到 $ f[3][j+2] $ ,从 $ f[3][j] $ 转移到 $ f[1][j+2] $ 。

猜你喜欢

转载自www.cnblogs.com/cyanic/p/9159518.html
今日推荐