CF 做题记录

CF1784C

弱化版就是将序列进行排序,设 a 的排名为 k,如果 a<k,就将 a 删除(后面的数排名也相应减一),否则将 ak 加入到答案中。

现在我们考虑每次加一个数,对答案的影响:我们加入一个数 x,会让大于 x 的数的排名加 1,这时候,如果在加入 x 前存在一个数 a,它的排名 k=a,那么这个数就要删掉。

因此,我们要找到最近的大于 x 且满足上述条件的 a,并把它删除。之所以找最近的,是因为删除 a 后会让大于 a 的排名减一,抵消了加入 x 的1排名变化。

因此我们考虑开一个权值线段树,维护 cnta[l,r] 的个数;sum :只考虑 [l,r] 这些数的答案(操作次数);Mn[l,r] 中,权值减去排名的最小值。

Mn[root]<0 时,就说明有数需要删除,通过线段树二分删除即可。

代码


CF1784D

考虑构造一个序列 a0=0<a1<a2<a3<...<an,获奖的人是 an,与 ai 比赛的是 ai+1,统计这种序列的方案数是多少。

我们默认 ai+1 都是 ai 的右儿子。

显然,ai 的子树内一定都是 ai 的数。

对于 ai 的左子树,它的根一定是 ai,而且它的排列方式有 (2ni1)!

由于 ai+1 会选走 2ni1 个数(也就是相当于内定了),因此左子树所选的数的方案数(mai2ni12ni11)。(m=2n1

因此 ai 的左子树总的方案数就有:

(mai2ni12ni11)×(2ni1)!

所以,对于构造的序列,它的总方案数:

i=0n(mai2ni12ni11)×(2ni1)!

由于 ai+1ai 的左儿子还是又儿子都没有影响,因此方案数还要乘上一个 2n

我们考虑怎么一般化。

我们设 dp[i][j] 表示 j 放在 ai 时的方案数。

显然,dp[i][j] 是从 k=0j1dp[i1][k] 再乘上那一坨系数转移过来的,这个可以用前缀和优化。

最后,dp[n][i]×2n 就是 i 获奖的方案数。

代码


CF513F2

显然,只有 |ab|<1 才有解,那个万能棋自然转化为少的那一种。

由于是同时移动,那么答案应该是移动时间最长的那个棋子,因此我们考虑二分答案 mid

预处理出每个点之间的距离。对于一个红色棋子 p,如果它走到 (x,y) 这个位置的时间 mid,那么我们就从 p(x,y) 连出一条流量为 1 的边;如果是蓝色棋子就反过来连即可。

连完边后,我们就跑一遍最大流,如果得到的答案是 max(a,b),那么说明这个时间是可行的。

由于点数为 n2,边数为 n4,那么时间复杂度是 n6logmaxt,但由于这个图类似于二分图,实际过程中不可能跑满,因此可过。

代码


CF1372E

首先,有一个贪心的想法,就是我们应该将 1 尽可能填在同一列上。

我们考虑用区间 DP:设 dp[i][j] 表示只考虑分段是 [i,j] 的子集的最优答案。

现在考虑如何合并出 [i,j]:我们枚举中间点 ikj,那么有转移为 dp[i][j]=dp[i][k1]+dp[k+1][j]+vali,j,k。其中 vali,j,k 表示分段包含 k 这个位置,且分段是 [i,j] 的子集的个数。

我们可以用高维前缀和预处理出 val

时间复杂度为 n3

代码


CF1740F

对于合并后的集合,如果长度不足 n 的,我们用空集补到长度为 n,这与原问题等价。并将元集从大到小进行排序。

对于两个元集 ai,aj,如果有 |ai|>|aj|,显然我们可以将 ai 中的一个元素移到 aj 中。

因此,对于两个集合 M,N,如果有 k[1,n], i=1k|Mi|i=1k|Ni|,那么 N 也是一个合法的构造。

我们可以设计一个状态:dp[i][j][k] 表示考虑到前 i 位,长度和为 j,上一个选的是 k,那么转移就是显而易见的了。

但这样似乎是 O(n3),显然过不了。

但我们可以发现,第 i 位选择的长度不会超过 n/i,这是调和的。

而且对于第 i 位,它的长度和上限为 j=1nmin(i,cntj)

代码


CF1646F

如果每个人手上都拥有 1n 的牌,我们只需要通过 n(n1)2 次交换,就能完成要求。

因此我们现在的目标就是使每个人手上都是 1n 的牌。

每轮我们重复以下操作:

  1. 先找到 1 个手上有重复牌的人,将其中一张重复牌传下去;

  2. 如果下一个人手上没有重复牌,就将与上一个人传递的相同的牌传下去;否则传递重复的牌。

这个操作显然也不会超过 n(n1)2 次。

代码


CF982F

题目就是要我们找到所有环的交点

我们先找出一个主环,然后将这些点都“删掉”,再找一次环,如果能找到,说明答案为 1

接着,我们对主环上每个点 u,找到它不经过主环的边能到达主环上最远的点 v(如果能到自己那就是最远的),那么我们将 uv 的主环点都进行标记(利用差分),它们显然不能成为答案。

找到一个可能成为答案的点后,把这个点删除再跑一次找环,没找到的话,说明这个点就是答案。

有亿些细节。

代码


CF325E

有一个神奇的方法,但我并不会证明。

首先,只有 n 为偶数有答案

我们考虑从后往前决策答案,由于后一个数奇偶性确定,那么操作也确定。

而我们的决策是优先选择 n/2 的数,如果被选过了,就选 <n/2 的。

也就是说,如果当前数为 ai=x,那么 ai1 优先选 x/2+n/2,否则选 x/2

代码


CF1606F

显然,我们能删除的点不会超过 n/k 个。

因此我们考虑用根号分治。

  1. kn 时,我们直接统计答案:设 f[i][j] 表示当 k=j 时,i 子树的最大答案。

  2. k>n 时,我们设 f[i][j] 表示 i 子树删除 j 个点后,i 拥有的子结点的最大值。

代码


CF773E

我们 F 的变化一定是先一直减小,然后单调不降

我们假设找出这个转折点 p,设 f[i] 表示操作到 i 的答案,那么转移为 f[i]=min(f[i1]+1,a[i])

将它展开,有:

ans=min(a[p]+np,...,a[n1]+1,a[n])

稍作转化,我们就可以维护 a[i]i 的最小值 Mn,答案就是 Mn+nn 为当前数的个数),可用线段树维护。

对于 p 这个点,我们直接在线段树上二分即可:当 ai>i 时,说明还可以继续减,向右移;反之向左移。

代码


CF1566F

我们可以先将开始就有点在上面的线段,以及有另一条线段是自己子集的线段给剔除。

那么现在就变成:(一堆线段) - 一堆点 - 一堆线段 - ... - 一堆点 - (一堆线段)

我们可以将一堆线段分给它左右两边的点;一个点可能要标记它两边的线段,因此最多会折返一次。

因此我们设 dp[i][0/1] 表示 i 点先向左 / 右走的最优答案。

对于向右走,我们将它放到 i+1 进行处理,这样方便我们切分同一堆线段。

DP 的时间复杂度为 O(n+m)

代码


CF1473F

一道网络流的好题。

一个经典的套路,将点分别与源点汇点相连,然后跑最小割,与源点相连表示不选,与汇点相连表示选。

但它有负权,我们考虑对连边做出一些修改:

  1. 如果 bi<0iT 连出一条流量为 bi 的边。

  2. 如果 bi>0,那么 Si 连出一条流量为 bi 的边。

  3. 对于 i<jai|aj,那么 ij 连出一条流量为 INF 的边。

这样,我们就可以跑最小割了。答案就是正点权和 最小割,

但边数有些超标,实际上我们第 3 边不需要全连,我们只需要枚举 ai 的约数 p,与 p 最后一次出现的位置连边即可。

代码


CF611E

一个大力分类讨论题。

首先,如果有 t>a+b+c,那么我们是无法完成任务的。

对于 b+c<ta+b+c,那么必须要三个人一起完成。

对于 a+c<tb+c,必须要 b, c 共同完成,而此时 a 也不能闲着,让他去从他能够打败的最大生命值的怪兽开始,能打一些是一些。

对于 max(a+b, c)<ta+c,和上一种情况同理。

如果 c<a+b,那么还要处理 c<ta+b 的,处理方式和上一种一样。

接下来就是单独一个人能处理的怪兽了。

我们只需要本着优先处理自己能打败的最大生命值的怪兽的原则,进行分类讨论即可。

细节见代码。

代码


CF1142D

打表找规律。

我们令 c 为排名 mod 11 后的值,我们可以发现,对于 c 相同的数,在它们后面接上一位 x,得到的新数的 c 也是相同的(假设新数是合法的话)。

打表可以观察出变化的规律,将其预处理出来。

然后我们设 dp[i][j] 表示以 si 结尾,排名 mod 11j 的个数。

跑一遍 DP 即可,记得开 long long。

代码


CF1685C

结论:不超过两次,一定可以将括号归位。

证明:我们将左括号看为 1,右括号看为 1,令 ai 表示 i 的前缀和。

我们找到最大的 ax,并翻转 [1,x], [x+1,2n]。对于 i[1,x],翻转后有 bi=axaxi0。对于 i[x+1,2n],翻转后有 bi=axan+xi0

接下来,我们只需要判断是否可以通过一次来完成。

假设翻转 [l,r] 可以满足,那么一定有 i[1,l), ai0i[r,2n], ai0

因此我们贪心地选择 al1 最大,ar 最大的位置进行判断即可。

代码


CF1469E

首先,无解的条件非常苛刻。

它必须满足 02k1 的二进制数,在串 α 的子串中都出现过。

因此,最后的答案有一段很长的前导零,有效部分长度不超 20

我们可以每次贪心地从高位开始填 01。假设到第 i 位,我们先填零,然后看 1i 位都与答案相反的情况下,α 是否有 2ki 种不同的子串。

代码


CF1713F

我们考虑 a 数组如何推到对角线。

为了方便,我们将 a 和对角线的横坐标从右往左重新编号 0n1

那么 ai 会对对角线位置 j 贡献 C(i,j) 次。

显然,如果要 C(i,j)mod2=1,那么必须满足 ji 的子集。

因此,对 a 做一次超集和,就能得到对角线的值。

同理,由对角线推 b,就是做一次子集和。

现在要求倒过来,那么就是做子集和的逆,以及超集和的逆。

但由于基础操作是异或,因此我们不用考虑容斥系数的影响。

代码


CF1392G

我们设 w(a,b) 表示 a,b 相同位置的个数; ai 表示 a 执行了 [i,1] 的操作,bi 表示 b 执行了 [i,1] 的操作,a 表示 a 执行了 [r,l] 的操作。

那么就有一个结论:w(ar,bl1)=w(a,b)

而且,如果我们知道 ab 的相同位置的 1 的数量,我们就能推知 w(a,b)

因此,我们考虑维护 f[0][S]=min{i|Sai}, f[1][S]=max{i|Sbi}

然后我们枚举 a,b 公共 1 的状态 s,检查 f[1][s]f[0][s] 是否 m 即可,如果是就更新答案。

代码


CF1149D

显然,在一个由 a 边连通的图中,他们的 b 边是没有用的。

因此,我们将原图看成若干个连通块,两两之间由一些 b 边连接。

对于两个连通块,他们之间最多只会选择一条 b 边,作为生成树的树边。

因此我们可以设计一个状态:f[S][u]S 表示已经离开的连通块,现在在 u 这个点,1u 的最短距离。

这个需要用最短路来更新。

但这样状态 S 就已经达到了 2n,显然存不下。

我们再观察,可以发现对于点数 3 的连通块,我们并不用记录。因为从一个连通块再回来至少经过 2b 边,而内部只需要经过 2a 边就能互相到达,因此不会影响答案。

这样时空就压到了 2n/4 了。

代码


CF1375F

本来是一道很简单的题,但开始想错方向了...

可以想到,先手是必胜的:当他构造出一个等差数列,且后手不能操作最大那堆石子时,先手就赢了。

因此我们来分类讨论一下,假设 a<b<c

如果后手选择操作 a,那么需要给出的 k 要满足 cb=a+kc,那么 k=2cba

如果后手选择操作 b,那么需要给出的 k 要满足 ca=b+kc,那么 k=2cba

但先手如果选择操作 c,那么我们就没有好方法了。

实际上,我们可以先加一个极大的数(如 1e10),那么无论后手加到哪堆,那堆都会成为最大堆,那么下一次他就无法操作最大堆了。

代码


CF1218G

一个朴素的想法,对于第 i 堆点,我们希望它们的点权满足 cii(mod3)

我们先跑出一棵生成树,对于非树边,边权都设为 3

考虑遍历这棵树。对于当前点 u,如果他的点权不满足上面的条件,那么我们就确定他到父亲那条边的边权。

但对于根节点,我们无边可改,这时候我们只能找出一个奇环,对环上的边交替 +1/+2,就能在不改变其他点的权值下修改根节点。

但如果不存在奇环,就无法完成操作。

这时候显然是一个二分图,我们考虑将点重新编号为 1/2,每个点依旧要满足 cii(mod3),注意还是模 3,而且默认根节点属于 1

对于根节点 r,我们分情况讨论:

  1. 如果 cr0(mod3),那么我们不需要修改,因为他的权值一定和相邻的点不同。

  2. 否则,此时 cr2(mod3)。如果根只有一个儿子 u,那么显然 u 的度数大于 1,他们的权值一定不同;如果不止一个儿子,那么我们可以任选两个儿子,将连接的两条边权值都加 1,就能让 cr1(mod3)cu,cv0(mod3)

代码


CF1634F

tag:差分

斐波那契数列看起来就有很好的差分性质。

我们令 ci=aiai1ai2di=bibi1bi2

显然,如果 C 序列与 D 序列相同,那么代表 A,B 也相同。

而我们在 a[l,r] 加上一段斐波那契数列,就相当于在 cl 加上 f1cr+1 减去 frl+2cr+2 减去 frl+1b[l,r] 同理。

代码


CF1041F

我们将上层点标为 0,下层点标为 1,我们假设从 (0,0)(即上层点第 0 号点)开始反射。

我们手推一下,发现如果我们步长取 x,那我们会经过的点就是 (0,0),(1,x),(0,2x),(1,3x)...

而如果我们再取 3x,那么上面能覆盖到的点就包括了这次覆盖的点了。

因此,我们的步长只会取 2k,kN,就可以在 O(nw),w=30 内处理出答案。

代码


__EOF__

本文作者zuytong
本文链接https://www.cnblogs.com/zuytong/p/17185383.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zuytong  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示