CF 做题记录

CF1784C

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

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

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

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

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

代码


CF1784D

考虑构造一个序列 \(a_0=0<a_1<a_2<a_3<...<a_n\),获奖的人是 \(a_n\),与 \(a_i\) 比赛的是 \(a_{i+1}\),统计这种序列的方案数是多少。

我们默认 \(a_{i+1}\) 都是 \(a_{i}\) 的右儿子。

显然,\(a_i\) 的子树内一定都是 \(\ge a_i\) 的数。

对于 \(a_i\) 的左子树,它的根一定是 \(a_i\),而且它的排列方式有 \((2^{n-i-1})!\)

由于 \(a_{i+1}\) 会选走 \(2^{n-i-1}\) 个数(也就是相当于内定了),因此左子树所选的数的方案数\(\begin{pmatrix} m-a_i-2^{n-i-1} \\ 2^{n-i-1}-1 \end{pmatrix}\)。(\(m=2^n-1\)

因此 \(a_i\) 的左子树总的方案数就有:

\[\begin{pmatrix} m-a_i-2^{n-i-1} \\ 2^{n-i-1}-1\end{pmatrix}\times (2^{n-i-1})! \]

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

\[\prod_{i=0}^n \begin{pmatrix} m-a_i-2^{n-i-1} \\ 2^{n-i-1}-1\end{pmatrix}\times (2^{n-i-1})! \]

由于 \(a_{i+1}\)\(a_{i}\) 的左儿子还是又儿子都没有影响,因此方案数还要乘上一个 \(2^n\)

我们考虑怎么一般化。

我们设 \(dp[i][j]\) 表示 \(j\) 放在 \(a_i\) 时的方案数。

显然,\(dp[i][j]\) 是从 \(\sum_{k=0}^{j - 1}dp[i-1][k]\) 再乘上那一坨系数转移过来的,这个可以用前缀和优化。

最后,\(dp[n][i]\times 2^n\) 就是 \(i\) 获奖的方案数。

代码


CF513F2

显然,只有 \(|a-b|<1\) 才有解,那个万能棋自然转化为少的那一种。

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

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

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

由于点数为 \(n^2\),边数为 \(n^4\),那么时间复杂度是 \(n^6\log maxt\),但由于这个图类似于二分图,实际过程中不可能跑满,因此可过。

代码


CF1372E

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

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

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

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

时间复杂度为 \(n^3\)

代码


CF1740F

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

对于两个元集 \(a_i, a_j\),如果有 \(|a_i|>|a_j|\),显然我们可以将 \(a_i\) 中的一个元素移到 \(a_j\) 中。

因此,对于两个集合 \(M,N\),如果有 \(\forall k\in[1, n],~\sum_{i=1}^k |M_i|\ge \sum_{i=1}^k |N_i|\),那么 \(N\) 也是一个合法的构造。

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

但这样似乎是 \(O(n^3)\),显然过不了。

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

而且对于第 \(i\) 位,它的长度和上限为 \(\sum_{j=1}^n min(i,cnt_j)\)

代码


CF1646F

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

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

每轮我们重复以下操作:

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

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

这个操作显然也不会超过 \(\frac{n(n-1)}{2}\) 次。

代码


CF982F

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

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

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

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

有亿些细节。

代码


CF325E

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

首先,只有 \(n\) 为偶数有答案

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

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

也就是说,如果当前数为 \(a_i=x\),那么 \(a_{i-1}\) 优先选 \(x/2+n/2\),否则选 \(x/2\)

代码


CF1606F

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

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

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

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

代码


CF773E

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

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

将它展开,有:

\[ans=min(a[p]+n-p, ..., a[n-1] + 1, a[n]) \]

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

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

代码


CF1566F

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

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

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

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

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

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

代码


CF1473F

一道网络流的好题。

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

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

  1. 如果 \(b_i<0\)\(i\)\(T\) 连出一条流量为 \(-b_i\) 的边。

  2. 如果 \(b_i>0\),那么 \(S\)\(i\) 连出一条流量为 \(b_i\) 的边。

  3. 对于 \(i<j\)\(a_i|a_j\),那么 \(i\)\(j\) 连出一条流量为 INF 的边。

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

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

代码


CF611E

一个大力分类讨论题。

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

对于 \(b+c<t\le a+b+c\),那么必须要三个人一起完成。

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

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

如果 \(c<a+b\),那么还要处理 \(c<t\le a+b\) 的,处理方式和上一种一样。

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

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

细节见代码。

代码


CF1142D

打表找规律。

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

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

然后我们设 \(dp[i][j]\) 表示以 \(s_i\) 结尾,排名 \(\bmod~11\)\(j\) 的个数。

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

代码


CF1685C

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

证明:我们将左括号看为 \(1\),右括号看为 \(-1\),令 \(a_i\) 表示 \(i\) 的前缀和。

我们找到最大的 \(a_x\),并翻转 \([1,x],~[x+1,2n]\)。对于 \(i\in[1,x]\),翻转后有 \(b_i=a_x-a_{x-i}\ge0\)。对于 \(i\in[x+1,2n]\),翻转后有 \(b_i=a_x-a_{n+x-i}\ge 0\)

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

假设翻转 \([l,r]\) 可以满足,那么一定有 \(i\in[1,l),~a_i\ge 0\)\(i\in[r,2n],~a_i\ge 0\)

因此我们贪心地选择 \(a_{l-1}\) 最大,\(a_r\) 最大的位置进行判断即可。

代码


CF1469E

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

它必须满足 \(0\sim 2^k-1\) 的二进制数,在串 \(\alpha\) 的子串中都出现过。

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

我们可以每次贪心地从高位开始填 \(0\)\(1\)。假设到第 \(i\) 位,我们先填零,然后看 \(1\sim i\) 位都与答案相反的情况下,\(\alpha\) 是否有 \(2^{k-i}\) 种不同的子串。

代码


CF1713F

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

为了方便,我们将 \(a\) 和对角线的横坐标从右往左重新编号 \(0\sim n-1\)

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

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

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

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

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

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

代码


CF1392G

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

那么就有一个结论:\(w(a_r,b_{l-1})=w(a',b)\)

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

因此,我们考虑维护 \(f[0][S]=\min\{i|S\subset a_i\},~f[1][S]=\max\{i|S\subset b_i\}\)

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

代码


CF1149D

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

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

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

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

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

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

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

这样时空就压到了 \(2^{n/4}\) 了。

代码


CF1375F

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

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

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

如果后手选择操作 \(a\),那么需要给出的 \(k\) 要满足 \(c-b=a+k-c\),那么 \(k=2c-b-a\)

如果后手选择操作 \(b\),那么需要给出的 \(k\) 要满足 \(c-a=b+k-c\),那么 \(k=2c-b-a\)

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

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

代码


CF1218G

一个朴素的想法,对于第 \(i\) 堆点,我们希望它们的点权满足 \(c_i \equiv i \pmod 3\)

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

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

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

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

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

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

  1. 如果 \(c_r \equiv 0 \pmod 3\),那么我们不需要修改,因为他的权值一定和相邻的点不同。

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

代码


CF1634F

tag:差分

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

我们令 \(c_i=a_i-a_{i-1}-a_{i-2}\)\(d_i=b_i-b_{i-1}-b_{i-2}\)

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

而我们在 \(a[l,r]\) 加上一段斐波那契数列,就相当于在 \(c_l\) 加上 \(f_1\)\(c_{r+1}\) 减去 \(f_{r-l+2}\)\(c_{r+2}\) 减去 \(f_{r-l+1}\)\(b[l,r]\) 同理。

代码


CF1041F

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

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

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

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

代码

posted @ 2023-03-06 20:44  zuytong  阅读(38)  评论(0编辑  收藏  举报