CF problems
多刷 CF,锻炼思维。
1987D(1800)
注意到 Alice 每一轮只会吃所有满足条件的蛋糕中最小的一个,并且只要她吃了同美味值的蛋糕中的一个,这个美味值的蛋糕就没用了,所以 Bob 想达到目的肯定要将同美味值的一组蛋糕全部吃掉。设 \(f_{i,j}\) 表示当前考虑到第 \(i\) 组蛋糕,当前 Bob 有 \(j\) 的空闲时间的最小贡献。设 \(c_i\) 表示美味值为 \(i\) 的有多少个。转移:\(f_{i,j}=\min\{f_{i+1,j+1}+1,f_{i+1,j-c_i}\}\),其中 \(j \geq c_i\)。时间复杂度 \(O(n^2)\)。好题。code
1981C(1800)
不妨设所有不等于 \(-1\) 的 \(a_i\) 组成序列 \(\{c_k\}\), \([1,c_1]\) 和 \([c_k,k]\) 我们只要不断操作就行了,而 \([c_i,c_{i+1}]\),只要注意到在一棵二叉树上,节点 \(i\) 的父节点编号正好是 \(\lfloor\frac{i}{2}\rfloor\),那么我们的问题就转化为求节点数为 \(V\) 的二叉树上 \(c_i\) 到 \(c_{i+1}\) 的长度为 \(x\) 的路径。复杂度 \(O(n\log V)\),实现上可能是 \(O(n\log^2 n)\) 的。好题!也可以考虑每一次除以二相当于二进制表达扣掉末尾一位,乘二相当于二进制表达末尾加上一位,然后将问题转化。code
1979D(1800)
可以知道满足 \(k-proper\) 的 01 串只可能是每 \(k\) 个数相等,相邻的两组 \(k\) 个数不相同。枚举 \(p\),用字符串哈希判断字符串相等即可。不如前面两个题好。code
1656H(3200)
画风突变。设 \(a_i=\prod\limits_{j=1}^{k_i} p_j^{\alpha_j}\),若 \(\alpha_i > \max\limits_{x \in S_B} \{\log_p x\}\),那么 \(a_i\) 就只能删掉了。定义 \(v_p x\) 表示 \(x\) 的质因数分解中 \(p\) 的指数。则该条件可表示为:
暴力判断显然过不了。考虑到我们的操作其实是求 \(\gcd\),单点删除。对于每个 \(a_i\) 和 \(b_i\) 维护一颗 seg,对于 \(a_i\) 的这棵 seg,每编号为 \(j\) 的叶节点维护 \(\frac{a_i}{\gcd(a_i,b_j)}\),单点删除就相当于把这个点的值改为 \(0\)。复杂度 \(O(n^2 \log n \log V)\),其中 \(\log V\) 是 \(\gcd\) 的复杂度,用 pbds 可能能把这个消掉。code
1994E(2000)
显然 \(k=1\) 时的答案就是这棵树的节点数。我们可以通过砍叶子结点的方式得到 \(1\) 到 \(siz\) 的所有数值。问题就变成了如何选数,也就是 \(ans\) 需要这个 \(siz\) 的哪几位做出贡献。一位一位考虑就可以了。只要想通前两句话,这个题就很好写。诈骗题。code
13E(2700)
弹 飞 绵 羊。code
616E(2200)
最主要的是整除分块的结论及其证明。
方便起见,我们设 \(f(x)=\lfloor\frac{n}{x}\rfloor\)。
对于右面这一坨整除分块。注意到 \(f(k)\) 的下降是阶梯状的,我们考虑对于每个阶梯的值算出来再乘上这一段区间内 \(k\) 的和就可以了。对于 \(i,j\),如果 \(f(i)=f(j)\),则 \(j\) 的最大值是 \(f(f(i))\)。
证明
设 $k=f(i)$,可知 $k \leq \frac{n}{i}$。可推出:故 \(j\) 取 \(\max\) 时 \(\forall i\) 满足条件,\(i=i_{\max}=f(k)=f(f(i))\)。\(\square\)
于是我们就可以在 \(O(\sqrt n)\) 的时间内完成求和。code
1045G(2200)
紫色的 2200。三维偏序问题的变形。将坐标离散化,搞出坐标左右端点在离散化结果上对应的区间,注意到 \(i,j\) 两个人能互相看到条件是(不妨设 \(x_i \geq x_j\)):
结合 (1)(2) 式,可得
可推出 \(r_i \leq r_j\)。
考虑将 \(r\) 作为三维偏序中的一维,将 IQ 值作为另一维,\(x\) 值作为第三维,我们以 \(r\) 排序,分治过程中对左右两端。这里顺便写一下 CDQ 分治的思想和方法。
CDQ 分治主要解决关于点对的问题,是离线做法。递归求解区间 \((l,r)\) 上包含的点对时,将 \((l,r)\) 拆成 \((l,mid)\) 和 \((mid+1,r)\) 两段,对于 \(i,j \in [l,mid]\),递归求解;对于 \(i,j \in (mid,r]\),递归求解;对于 \(i \in [l,mid],j \in (mid,r]\),单独设计算法求解。伪代码:
solve(l,r){
mid=(l+r)/2
solve(l,mid),solve(mid+1,r)
solve the third situation
}
1228E(2300)
容斥。先讲原理。对于 \(n\) 个集合 \(S_1,S_2,\dots,S_n\),我们有:
其中 \(a\) 是 \({x\in \mathbb Z|1\leq x\leq n}\) 的一个子集。可以通过 \(n=3\) 的情况来类比得到证明。
回到这个题。我们考虑每一行合法的情况数就是 \(k^n-k^{n-1}\)。正难则反,我们考虑让列不合法。情况数就是分别选 \(1\) 到 \(n\) 列,让他们不合法,选 \(i\) 列不合法的情况数是:
有因为每一列的情况是等价的,所以总情况数就只用取个 \(n\) 次方,乘上 \(n \choose i\),这就是容斥公式中的 \(\sum\limits_{a_i\le a_{i+1}}|\bigcap\limits_{i=1}^m S_{a_i}|\) 部分,然后我们套公式就可以得到答案是:
然后就可以了。代码很短。code
1787H(3300)
答案最优就是损失最少。由题意,我们有:
记 \(c_i=b_i-a_i\),则 \(Ans=\sum_{i=1}^n b_i -\sum_{i=1}^n\min\{k_i\cdot t,c_i\}\)。如果我们钦定一部分题目花费 \(c_i\) 的代价,则剩下的题目应当贪心地将 \(k_i\) 降序排列(排序不等式)。设 \(f_{i,j}\) 表示 \(i\) 个数中钦定 \(j\) 道题得 $k \cdot t $ 的最小代价,有转移:
时间复杂度是 \(O(n^2)\) 的,考虑在转移过程中优化。打个表发现 \(f_{i,j}\) 关于 \(j\) 是凸的(你问我怎么想到的,汪娟会告诉你,这就是你与 CF rating 3300 的区别)。于是我们设 \(g_{i,j}\) 表示 \(f_{i,j}-f_{i,j-1}\),然后用它改写 DP 式子得到:
我们发现上式的元太多了,于是我们将上式记为(1)式。然后用 \(j-1\) 代替 \(j\) 后改写上式,得:
将上式记作(2)式,用(1)式减(2)式,得:
\(k\) 是不增的。注意到 \(g_{i,j}-g_{i,j-1} \geq k_i\),接下来我们尝试证明这个性质。
对 $g_{i,j}-g_{i,j-1}\geq k_i$ 的证明
运用数学归纳法。
当 \(i=2\) 时,结论显然成立;
若 \(i=i\) 时成立,则,当 \(i=i+1\) 时,有:
观察 \(\min\{g_{i,j}+c_i,k_i \cdot j\}\) 这一项,发现 \(\Delta g_{i,j}\geq \Delta k_i \cdot j\),则存在一个 \(pos\) 使 \(\forall j \leq pos,g_{i,j}\leq k_i\cdot j,\forall j \geq pos,g_{i,j} \geq k_i \cdot j\),则由 \(g_{i-1}\) 变换到 \(g_i\) 的过程如下:\(j \le pos\) 的位置不变。\(j \ge pos\) 的位置的值加 \(k_i\) 。中间插入 \(k_i \cdot j - c_i\)。
于是我们只用考虑中间位置与其左右两边的差就可以了。
可证明
由此我们可以找到一个位置 \(pos\) 使得 \(\forall j \leq pos,g_{i,j}\leq k_i\cdot j,\forall j \geq pos,g_{i,j} \geq k_i \cdot j\)。于是从 \(g_{i-1}\) 推到 \(j_{i}\) 就变得简单了起来。我们用平衡树维护 \(g_i\),就可以把时间复杂度做到 \(O(n\log n)\)。这种在斜率上操作的方法叫 Slope Trick。code
1187E(2100)
换根 DP 好题。首先我们注意到最后的结果在我们选出第一个填黑色的节点的时候就已经确定了,于是我们设 \(g_i\) 表示 \(i\) 为第一个填黑色的节点时的答案,直接求 \(g_i\) 不是很方便,于是我们考虑设 \(f_i\) 表示选了 \(i\) 后其子树对答案的贡献。可得 \(f_i=siz_i+\sum_{j \in son\{i\}}f_j\),得到 \(g_1=n+\sum_{\{j,1\}\in E}f_j\),如果每次都求一遍复杂度为 \(O(n^2)\),考虑换根 DP。先求出 \(g_1\),然后考虑 \(g_i\) 的递推式,这玩意显然要自上向下推,设 \(i=fa_j\),易得(虽然我得来并不易) \(g_j=n+(n-siz_j)+\sum_{k \in son\{i\},k \neq j}f_k+\sum_{k \in son\{j\}}f_k\),稍微推一推,得 \(g_j=g_{i}-2siz_j+n\),然后就 \(O(n)\) 地过掉了。code
506D(2400)
先考虑暴力,每次枚举颜色,在查询的时候如果两点只用同一种边就能联通,那么这个颜色对答案贡献加一,维护联通用并查集,时间复杂度 \(O(qm\log n)\),在颜色数很小的时候可以过。再考虑另一种暴力,先对每一种颜色分别建图,然后枚举这上面的每个点对查询,如果联通则贡献加一,时间复杂度 \(O(mn^2\log n)\),在 \(n^2<q\) 的时候会比前一种情况优。
接下来考虑如何优化,这里使用根号分治。注意到如果当前颜色的边数小于 \(\sqrt m\) 的时候,这样所有这样的颜色的连通块的点的总数的平方和不超过 \(n\sqrt n\),于是可以用第二种暴力,时间复杂度 \(O(n\sqrt n \log n)\);如果当前颜色边数大于 \(\sqrt m\),那么满足这个条件的颜色数最多 \(\sqrt m\),故使用第一种暴力,时间复杂度 \(O(\sqrt m q\log n)\),加一块,稳稳过。code
809C(2600)
先把 \(a\) 的表打出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15 18 17 20 19 22 21 24 23 26 25 28 27 30 29 32 31
3 4 1 2 7 8 5 6 11 12 9 10 15 16 13 14 19 20 17 18 23 24 21 22 27 28 25 26 31 32 29 30
4 3 2 1 8 7 6 5 12 11 10 9 16 15 14 13 20 19 18 17 24 23 22 21 28 27 26 25 32 31 30 29
5 6 7 8 1 2 3 4 13 14 15 16 9 10 11 12 21 22 23 24 17 18 19 20 29 30 31 32 25 26 27 28
6 5 8 7 2 1 4 3 14 13 16 15 10 9 12 11 22 21 24 23 18 17 20 19 30 29 32 31 26 25 28 27
7 8 5 6 3 4 1 2 15 16 13 14 11 12 9 10 23 24 21 22 19 20 17 18 31 32 29 30 27 28 25 26
8 7 6 5 4 3 2 1 16 15 14 13 12 11 10 9 24 23 22 21 20 19 18 17 32 31 30 29 28 27 26 25
9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8 25 26 27 28 29 30 31 32 17 18 19 20 21 22 23 24
10 9 12 11 14 13 16 15 2 1 4 3 6 5 8 7 26 25 28 27 30 29 32 31 18 17 20 19 22 21 24 23
11 12 9 10 15 16 13 14 3 4 1 2 7 8 5 6 27 28 25 26 31 32 29 30 19 20 17 18 23 24 21 22
12 11 10 9 16 15 14 13 4 3 2 1 8 7 6 5 28 27 26 25 32 31 30 29 20 19 18 17 24 23 22 21
13 14 15 16 9 10 11 12 5 6 7 8 1 2 3 4 29 30 31 32 25 26 27 28 21 22 23 24 17 18 19 20
14 13 16 15 10 9 12 11 6 5 8 7 2 1 4 3 30 29 32 31 26 25 28 27 22 21 24 23 18 17 20 19
15 16 13 14 11 12 9 10 7 8 5 6 3 4 1 2 31 32 29 30 27 28 25 26 23 24 21 22 19 20 17 18
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
18 17 20 19 22 21 24 23 26 25 28 27 30 29 32 31 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15
19 20 17 18 23 24 21 22 27 28 25 26 31 32 29 30 3 4 1 2 7 8 5 6 11 12 9 10 15 16 13 14
20 19 18 17 24 23 22 21 28 27 26 25 32 31 30 29 4 3 2 1 8 7 6 5 12 11 10 9 16 15 14 13
21 22 23 24 17 18 19 20 29 30 31 32 25 26 27 28 5 6 7 8 1 2 3 4 13 14 15 16 9 10 11 12
22 21 24 23 18 17 20 19 30 29 32 31 26 25 28 27 6 5 8 7 2 1 4 3 14 13 16 15 10 9 12 11
23 24 21 22 19 20 17 18 31 32 29 30 27 28 25 26 7 8 5 6 3 4 1 2 15 16 13 14 11 12 9 10
24 23 22 21 20 19 18 17 32 31 30 29 28 27 26 25 8 7 6 5 4 3 2 1 16 15 14 13 12 11 10 9
25 26 27 28 29 30 31 32 17 18 19 20 21 22 23 24 9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8
26 25 28 27 30 29 32 31 18 17 20 19 22 21 24 23 10 9 12 11 14 13 16 15 2 1 4 3 6 5 8 7
27 28 25 26 31 32 29 30 19 20 17 18 23 24 21 22 11 12 9 10 15 16 13 14 3 4 1 2 7 8 5 6
28 27 26 25 32 31 30 29 20 19 18 17 24 23 22 21 12 11 10 9 16 15 14 13 4 3 2 1 8 7 6 5
29 30 31 32 25 26 27 28 21 22 23 24 17 18 19 20 13 14 15 16 9 10 11 12 5 6 7 8 1 2 3 4
30 29 32 31 26 25 28 27 22 21 24 23 18 17 20 19 14 13 16 15 10 9 12 11 6 5 8 7 2 1 4 3
31 32 29 30 27 28 25 26 23 24 21 22 19 20 17 18 15 16 13 14 11 12 9 10 7 8 5 6 3 4 1 2
32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
打表程序:
int a[105][105],arr[205];
std::set<int> se;
int main(){
freopen("a.txt","w",stdout);int n=32,m=32;a[1][1]=1;
for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){
if(i==1&&j==1){continue;} se.clear();
for(int k=1;k<i;k++)se.insert(a[k][j]);
for(int k=1;k<j;k++)se.insert(a[i][k]);
int cnt=0; a[i][j]=-1;
for(auto x:se)arr[++cnt]=x;
if(arr[1]>1)a[i][j]=1;
else{for(int k=2;k<=cnt;k++){if(arr[k-1]+1!=arr[k]){a[i][j]=arr[k-1]+1;break;}}}
if(a[i][j]==-1)a[i][j]=arr[cnt]+1;
}
}for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]<10)std::cout<<" "<<a[i][j]<<" ";
else std::cout<<a[i][j]<<" ";
}std::cout<<"\n";
}
}
然后发现对于每一个大小为 \(2^k\) 的正方形(下文简称“\(k\) 正方形”)区域都均分成了四块,每一行、每一列都填满了 \(1\) 到 \(2^k\) 的排列(性质 1),并且左上角和右下角一样,右上角和左下角一样,都是左上角对应位置的数字加上 \(2^{k-1}\)(性质 2)。
对于矩形 \((n,m)\) 的询问,我们找最小的一个可以包住它的 “\(k\) 正方形”。注意到 \(a\) 关于主对角线轴对称,所以不妨设 \(n\geq m\),这样讨论矩形在 \(k\) 正方形中的位置。
如果 \((n,m)\) 在右下角,我们把 \(k\) 正方形分成四个 \(k-1\) 正方形,然后根据性质 1,我们可以利用求和公式求出要求的矩阵中左上角、右上角、左下角的和,对于右下角我们递归求解。
如果 \((n,m)\) 在右上角,左边那一块可以用求和公式求出,右半边递归求解,注意要加上 \(2^{k-1}\) 的偏移量。
这样就可以 \(O(可过)\) 了。code
1891F(2000)
正 难 则 反。code
837D(2100)
先设 \(f_{i,j,x,y}\) 表示 \(i\) 个数,选了 \(j\) 个,其中 \(x\) 个 2,\(y\) 个 5,是否可行。注意到不可过,于是将 \(x\) 这较大的一位放到结果,这相当于是某些题里把较小的答案放到状态里的反过程。设 \(f_{i,j,x}\) 表示 \(i\) 个数,选了 \(j\) 个,其中 \(x\) 个 5 的时候最多多少个 2,得到转移 \(f_{i,j,x} = \max\{f_{i-1,j-1,x-c5(i)},f_{i-1,j,x}\}\),压维,后两维倒叙就过了。code
1718A2(1900)
我们显然可以通过 \(n\) 次异或 \(a_i\) 来通过 \(n\) 的代价来把 \(a_i\) 全变成 \(0\),注意到如果一个长度为 \(len\) 的区间异或和是 \(0\),则这个区间定可以通过 \(len-1\) 的次数变成零,于是我们只需要统计这样的区间的个数,然后减掉这样的区间数就行了。code
359D(2000)
注意到 \(\exists k\in [l,r], \forall i\in [l,r], a_k|a_i \iff \min(a_l,a_{l+1},\dots,a_r)=\gcd(a_l,a_{l+1},\dots,a_r)\),于是二分区间长度,线段树维护 \(\min\) 与 \(\gcd\) 就行了。code
2040C(1600)
神秘题,场上被创飞了,从第一步就没想出来,但只要想到第一步问题就迎刃而解了。我们先考虑这个排列的生成方式。注意到我们只需要从 \(1\) 到 \(n\) 考虑填的位置(以上两句话我硬生生没想到,以后可以当做一个思维角度),于是发现每次这个数必然填在空白字符段的两端,这样每一个数都能做出最大贡献。于是我们发现一共有 \(2^{n-1}\) 种满足 \(S(p)\) 最大的排列。我们用一个二进制数来表示每一个数都放在了前端还是后端,于是我们发现这个二进制数正好对应着排名,于是把排名拆位就行了。code
622F(2600)
引理:设 \(f_k(x)=\sum_{i=1}^n i^k\),我们有 \(\deg f_k(x)=k+1\)。
证明:这里对 \(k\) 使用数学归纳法。
当 \(k=1\) 时,\(f_1(x)=\sum_{i=1}^x i = \frac{x(x-1)}{2}\),\(\deg f_1(x)=2\),成立;
如果当 \(k=n\) 时,\(\deg f_{n}(x) = n+1\);
那么当 \(k=n+1\) 时,\(f_{n+1}(x)=f_n(x)\cdot f_{1}(x)-g(x)\),其中 \(\deg g(x) < n+1\),故 \(\deg f_{n+1}(x)=\deg f_{n}(x)\cdot f_{1}(x)=n+1\),于是引理得证。
于是我们知道了 \(f_{k}(x)\) 的度数,这启发我们可以通过选择 \(k+2\) 个点来确定 \(f_k(x)\),然后利用拉格朗日插值法求出 \(f_k(n)\)。下面简记 \(f_{k}(x)\) 为 \(f(x)\)。
我们考虑选 \(x=1,2,\dots,k+2\) 的这些点,由拉格朗日插值,我们有
发现分子分母都可以预处理,于是 \(O(K)\) 直接过。code
785E(2200)
注意到交换 \(a_i,a_j\) 之后,相较之前的答案,如果 \(a_i<a_j\),\(ans+1\),否则 \(ans-1\),然后 \([1,i)\) 对答案的影响与 \((j,n]\) 对答案的影响没有任何变化,\((i,j)\) 能使 \(ans\) 加上两倍的小于 \(a_j\) 的数量再减去两倍的小于 \(a_i\) 的数量,分块维护小于 \(k\) 的数量就完了。code
1558D(2600)
仙品。注意到题目相当于告诉我们 \(m\) 组大小关系,让我们求可能的排列个数。如果我们知道小于号的个数 \(c\),那么使用插板法可得答案就是 \(C_{2n-c-1}^n\),于是问题转化为求 \(c\)。我们维护一个集合 \(S\),存储所有的前面是小于号的数,答案就是 \(\# S\),于是考虑一个条件 \(a_i<a_j\) 时,如果 \(j\) 不在 \(S\) 中,也就是说 \(a_j\) 前面是 \(\le\),那就把 \(j+1\) 插进去,并且把 \(S\) 中所有比 \(j\) 大的数加一。我们考虑如何用一个 DS 维护集合 \(S\),也就是说这个 DS 需要维护插入和区间加,于是想到平衡树。code
420D(2200)
反着考虑就完了。code
2013E(2200)
首先前缀 \(\gcd\) 是单调不升的,我们尽量在前面下降,然后降到 \(\gcd(a_1,\dots,a_n)\),然后直接停下,这样贪心就是对的,并且复杂度是 \(O(n\log n)\) 的,因为每一次下降最少降为原来的 \(\frac{1}{2}\),所以 \(n\log n\) 一般情况下跑不满,这样就过了。code
1301F(2600)
很自然地想到把颜色相同的点缩起来跑 Floyd,预处理原来的点不通过传送到缩起来后的点的距离,然后每次询问枚举第一次和最后一次在那个颜色传送,时间复杂度 \(O(nmk+qk^2)\),但是 \(qk^2\) 太大了。于是考虑直接搞点可以经过传送到某个颜色的距离,这个对每个颜色跑一遍 bfs 就行了。记 \(d(i,x,y)\) 表示点 \((x,y)\) 到颜色为 \(i\) 的点们的距离,答案就是起点与终点间曼哈顿距离与
取 \(\min\) 的结果。时间复杂度 \(O(k(nm+q))\),稳稳过。code
2078D(1800)
STO Wei_Han ORZ
从前往后看问题,发现问题具有后效性,没法 DP,折半也是不行的因为我们并不能很好地合并前后两端的答案,于是正难则反,考虑反着做,发现这样就没有后效性,只用考虑后几位的答案就行了。
再求值之前,我们先做一些操作。我们将左边的门编号为 \(0\),右边的门编号为 \(1\),我们设 \(a_{i,o}\) 表示第 \(i\) 关编号为 \(o\) 的门做乘法操作的倍数,如果是加法门,就令 \(a_{i,o}=1\),然后另计 \(b_{i,o}\) 表示加上的数。。我们设 \(f_{i,o}\) 表示考虑到第 \(i\) 个关卡左/右边的门对前面的决策产生的贡献。易知对于当前一个门,加法门所产生的贡献并不会对前面造成什么影响,而对于每个门产生的贡献,把这些贡献全部放到能产生更大贡献的那一边要比留一些在更劣的一边优,于是我们得到递推式
并且如果当前出现加法门,则使
并且在最后给答案加上 \(f_{1,0}+f_{1,1}\),时间复杂度 \(O(nT)\),好奇为什么 \(n\) 要放这么小。code
2092E(2100)
hint:对于有偶数个相邻块的块,它自己啥颜色对答案有关吗?
没有关!所以只用考虑边边上的就行了。然后就做完了。code
1716D(2000)
定义 \(f_{i,j}\) 表示第 \(i\) 个点被地第 \(j\) 次走到的方案数。列转移是容易的,但是转移复杂度太高。
考虑 \(j\) 这一位,发现它并不是 \(O(n)\) 的,而是 \(O(\sqrt n)\) 的,所以可以暂且不管这一维。然后就可以前缀和优化直接做了。代码我没写。
2091G(2300)
定义 \(f_{i,j}\) 表示走 \(j\) 步能否到达 \(i\),转移容易列出,但 \(i\) 的规模太大了,一些特殊的性质。发现当 \(s>k^2\) 的时候,两次一定可以,于是 \(i\) 的规模就变成了 \(10^6\),但这还是过不了,并且发现想不动了,于是挂个 bitset 就行了。
OI 中可以使用的动态 bitset: https://codeforces.com/blog/entry/129454
1091E(2400)
抽象没边了。
hint:链接最有效的一集。
Erdős–Gallai 定理:对于一个序列 \(d_1,d_2,\dots,d_n\),它可以成为一个简单无向图的度数的序列:等价于
\(2|(\sum d)\);
\(\forall k\in \{1,2,\dots,n\},\sum_{i=1}^k d_i\leq k(k-1)+\sum_{i=k+1}^n\min(d_i,k)\)。
对于 1,考虑每条边的贡献即可;对于 2,右边前一个式子是内部的,第二个式子是内部和外部的。
利用这个定理的朴素做法就是枚举 \(d_{n+1}\),判断是否可行,时间复杂度 \(O(n^2)\)。
尝试寻找性质,观察阳历发现,如果 \(d_{n+1}\) 是 \(x\) 或 \(y\) 时满足条件,那么对于所有 \(x<z<y\) 且 \(z\) 与 \(x,y\) 奇偶性相同,\(d_{n+1}=z\) 也是可以的。
于是将原序列排序,然后二分上下界。check 的时候考虑把当前值插入序列并保证序列单调性的位置就行了。时间复杂度 \(O(n\log n)\)。code
1149D(3000)
称边权为 \(a\) 的边为轻边,其余称为重边。我们发现去掉重边之后剩下的可以构成几坨连通块,并且如果一条路径在最小生成树上,那么它只会进出一个连通块最多一次。于是在连通块上 dp。设 \(f_{S,u}\) 表示当前走过的连通块的集合为 \(S\),当前走到点 \(u\) 的最短距离。由于 \(f_{S,u}\) 可以转移到 \(f_{S,v}\) 意味着反过来也是可以的,所以需要用最短路的方式 dp,时间复杂度 \(O(2^nm\log(2^nm))\),考虑优化。然后注意到对于 \(siz\leq 3\) 的连通块不需要考虑,因为走内部边总一进一出快,于是时间复杂度 \(O(2^{n/4}m\log(2^{n/4}m))\)。code
1764H(3400)
倒着做,考虑维护 \(t\) 表示每个位置上的数最多能活多久,然后每次操作相当于对 \((l\dots r]\) 上的点区间覆盖,对 \(l\) 上的点,\(t_l\leftarrow \max_{x=l+1}^rt_x\),其连续段个数综合是 \(O(n)\) 的,于是可以用 set 维护连续段,时间复杂度 \(O(n\log n)\),同时用树状数组数点,当前的答案就是 \(t_i>x+k-1\) 的位置。code
2134D(2300)
注意到一次滑行操作最多使直径加 1,所以我们的方法要尽量让每次操作都加 1,发现这是可行的,只需要找出一条边 \((u,v)\) 满足 \(u\) 在直径上而 \(v\) 不在,令 \(u\) 在直径上的前驱为 \(f\),那么 \(a=f,b=u,c=v\) 滑动一次就行。
803F(2000)
肇事一眼秒的题我场上不会/ll
子集相关问题要做 \(\text{polylog}(n)\) 的复杂度的话如果不能直接算基本上就是枚举子集长度或者答案,这里子集长度没有意义所以维护子集的答案。\(f(i)\) 表示 \(\gcd\) 为 \(i\) 的方案数。记 \(c_i\) 表示 \(i\) 出现的次数,考虑 \(i=\gcd(x,y)\) 的话 \(x,y\) 都是 \(i\) 的倍数,所以 \(f(i)\leftarrow 2^{\sum_{k\geq 1}f(ki)}-1\),但是这样会把 \(\gcd\) 为 \(ki\) 的方案数算进去,所以减掉 \(\sum_{k\geq 1}f(ki)\) 就行。codes。
1707C(2400)
边权互不相同所以最小生成树唯一。无向图 dfs 树只可能有树边和返祖边,对于每个根,FindMST 之后是 MST 的充要条件是所有非 MST 边都是返祖边。对于每个非 MST 边 \((u,v)\) 我们把 \((u,v)\) 两侧的子树的每个点加 1 因为只有这些点可以被计算进答案,树上差分维护即可。codes
1788F(2500)
路径异或和转化为点到根路径异或和的异或,\((u,v,w)\iff s_u\operatorname{xor}s_v=w\),考虑可行性问题,对于二元约束考虑建图,\((u,v)\) 边权为 \(w\) 来维护这样一个限制,如果环路上一个点取值有矛盾就无解。然后考虑最小化,通过 \(s_{fa}\operatorname{xor}s_u\) 得到 \((u,fa)\) 边上的边权,考虑每个前缀对异或和的贡献,如果这个点的度数为偶数那么这个点的前缀异或对于答案的贡献一定是 0,分别考虑每个连通块,如果连通块内度数为奇数的点数为偶数那么怎么修改都是没用的,否则一定可以修改为 0.codes
2150A(1300)
考虑第 \(i\) 个人前 \(i-2\) 步和第 \(i-1\) 个人前 \(i-2\) 步是完全一样的,只用维护倒数两步就行。code
2151C(1400)
对于确定的 \(k\),策略是在前 \(k\) 秒进人,后 \(k\) 秒出人然后中间保持每时每刻都有 \(k\) 个人。我们要算的是 \(\sum_{i=1}^ka_ii,\sum_{i=1}^ka_{2n-i+1}i\) 和中间的和可以前缀和后缀和直接做。code
2150B(1700)
发现 \((1,1)\) 和 \((1,n)\) 是必填的,并且对于一个 L 型,只可能填在竖着的那一列上,这意味着每一列只能填一个,然后考虑行的限制,发现从下往上扫每行能填的会越来越多所以直接从下往上扫算就完了。code
2150C(2100)
两个排列不好做,先建立 \(a_i\rightarrow i\) 的映射;设 Alice 选的是 \(S\),对于 \(x<y,x\not\in S,y\in S\),一定有 \(b^{-1}(x)<b^{-1}(y)\),考虑一个 dp,设 \(dp(i,j)\) 表示考虑到 \(a_{1\dots i}\),Bob 选的最大的 \(pos\) 是 \(j\),然后 seg 优化转移,注意 seg 维护区间最大值初始的最小值和区间无交时的 \(-\infty\) 要不同。code
2150D(2700)
考虑一个 \(p\) 合法的条件,设 \(f(i)\) 表示第 \(i\) 个位置上人的个数,发现合法当且仅当
- 不是 0 的 \(f\) 是连续的
- 不是 0 的 \(f\) 是奇数(除了最左边的和最右边的不是 0 的)
不妨先考虑连续段为 \([1\dots k]\) 的情况,有约束 \(\sum_{i=1}^kf_i=n\),发现不好维护的是左右端点,正常来说需要 \(O(n^2)\) 枚举,很不优。不妨设 \(a_1=2g_1+x,a_k=2g_k+y\),\(x,y\in \{1,2\}\),\(a_i=2g_i+1\),这样 \(g\) 的方案数可以插板求,然后每个 \(g\) 是公平的所以直接平均数乘上刚刚求出的方案数就得到了 \([1\dots k]\) 的方案数。对于整个问题可以枚举 \(k\),然后前缀和的前缀和解决。code
fun problems by ssfzzzc。按开题顺序写。不写题面。
1304C(1500)
tag: easy
维护当前可能的温度区间,每次强制与 \(l_i\) 取 max,\(r_i\) 取 min
1325D(1700)
tag: easy
异或和是 \(u\) 的话先扔一个 \(u\) 显然比一位位凑优得多,再凑 \(v-u\),如果 \(v-u\) 和 \(u\) 异或起来答案完全不变则直接两个数 \(\{u,v-u\}\) 否则 \(\{u,(v-u)/2,(v-u)/2\}\)。
1338B(1800)
tag: fun
对于最小的情况,如果所有叶子之间的路径长度均为偶数那答案一定是 1,否则注意到 \(1\operatorname{ xor }2=3\)让一束长度为奇数的路径的交上的边权都是 2,两边是 1 和 3 即可。统计路径长度只用对 \(dep\) 的奇偶性进行讨论,如果所有奇偶性都是一样的就没有偶数因为 \(-2dep(lca)\) 对答案的奇偶性没有影响。
对于最大的情况,发现只有一个点下面挂了两个叶子结点的时候这两个叶子之间的路径需要相同,否则必然可以不同。dfs 统计就行了。
1385D(1500)
tag: /bangbangt
int dif(int l, int r, int d) { return (r - l + 1) - (sum[r][d] - sum[l - 1][d]); }
void solve(int l, int r, int d)
{
if (l == r) return a[l] != d;
int mid = l + r >> 1;
int t1 = dif(l, mid, d) + solve(mid + 1, r, d + 1);
int t2 = dif(mid + 1, pr, d) + solve(l, mid, d + 1);
return min(t1, t2);
}
1396B(1800)
tag: guess
如果 \(mx>sum-mx\) 先手必胜否则必胜的那个人一定有方法能把所有都取了判断奇偶性即可。
1413C(1900)
tag: kind of fun
维护答案需要最小值和最大值,钦定一个差值为最大值然后 seg 查询其他的音符的差值的最大值的最小值。
1428D(1900)
tag: /tuu/tuu/tuu
对于 0 这一列就是空着的;
对于 2 从后面选一个 1;
对于 3 从后面 1/2/3 选一个 2 没选过的;
剩下的 1 填就完了。
看错题卡了我 1h+
1542B(1500)
tag: math
发现 \(n=a^x+by\),然后 \(\log_a n\) 算 \(a^x\) 就行了。
1542C(1600)
tag: math
拆贡献,\(i\) 的贡献就是 \(i(\lfloor\frac{n}{L_{i-1}}\rfloor-\lfloor\frac{n}{L_{i}}\rfloor)\),其中 \(L_i=\operatorname{lcm}(1,2,\dots,i)\)。
1548A(1400)
低的向高的连边,不死等价于出度为 0,动态维护答案即可。
欢迎回来
165E(2200)
\(a\operatorname{and} b=0\) 相当于 \(b\) 是 \(a\) 取反之后的子集,做高维前缀和状物即可。
1750F(2700)
妙妙题啊。
考虑一个串想要合并成一个全是 1 的串就相当于是中间所有的连续的 1 能合并起来,这不好维护,考虑反过来维护合并不起来的情况,这相当于每段 0 的长度都大于相邻的两个连续 1 段的和,发现这只与其相邻两端的 1 的长度有关,这启发我们将连续的 1 作为子结构,\(dp(i,j)\) 表示长度为 \(i\) 的串,两边为 1 且最后一段连续的 1 的长度是 \(j\) 的合法串数。我们有 \(dp(i,i)=2^{i-2}-\sum_{j=1}^{\lfloor\frac{i-1}{2}\rfloor}dp(i,j)\),对于 \(dp(i,j)\) 相当于是在 \(dp(j,j)\) 前面加上 0 连续段和一个 1 连续段结尾的串,有 \(dp(i,j)=dp(j,j)\sum_{k={j+2}}^{i-j-1}\sum_{l=1}^{k-j-1}dp(i-j-k,l)\),维护 \(sum(i)\) 表示 \(j+k\leq i\) 的 \(dp(i,j)\) 之和就可以做到 \(O(n^2)\)。
1748E(2300)
约束等价于大根笛卡尔树建出来相等,又发现保证了 \(\sum n\times m\) 的总量所以直接 \(dp(u,i)\) 表示笛卡尔树上节点 \(u\) 填了 \(j\) 的方案数,转移列出来就是 \(dp(u,i)=\sum_{j\leq i}dp(lc,j)\times \sum_{j< i}dp(rc,j)\),前缀和优化即可做到 \(\Theta(\sum n\times m)\)。
1725J(2500)
如果没有传送带答案就是 \(2\sum w-d\),\(d\) 是直径的长度。
挂上传送带相当于我们要选两条路径让着两条路径的长度和尽可能大,但是这道题还有约束就是说如果两条路径相交的话只能交于一点,如果两条路径不相交的话只能有一条是折线,说人话就是因为其中一条路径是起点到终点的路径,另一条路径必须是从这个路径往下单向延伸的,这很不好维护,但是边权非负所以这两条路径只隔了一条边。
对于交于一点的情况我们考虑交点。你发现把这个节点当根的话你要求的就是最大的四个 dep 的和,考虑换根 dp。从 \(u\) 向 \(v\) 转移的过程中有八条路径可选,分别是 \(v\) 底下的四个和 \(u\) 的四个加上 \(w(u,v)\),答案就是 \(\max\{\sum mxdep_{u,1/2/3/4}-\min\{mxdep_{u,1/2/3/4}\}\}\)。
对于隔一条边的情况我们考虑这条边,用底下的点维护,这条边的贡献是子树内的直径加子树外的最深或子树内最深加子树外的直径。换根维护就行。
换根 dp 的大杂烩,和起来成大粪了。放一下代码
555E(2800)
缩起边双来 \(s\rightarrow t\) 就只用管剩下那棵树上的方向就行了。
1767E(2500)
发现连续两个必须有一个被激活,所以 \(c_1,c_n\) 和自己连边,相邻的两个位置连边,答案就是最小覆盖,这等于总数减去最大独立集,状压枚举填了的颜色,有
然后转移不需要枚举 \(v\),只需要 v=64-__builtin_clzll(S) 就行了,meet in middle 就是 \(O(2^{m/2}m)\) 的。
1842G(2800)
考虑 \(a_i+kv\) 的贡献,用乘法分配律拆开,那么当前的贡献可能是
-
\(a_i\)
-
一个前面用过的 \(v\)
-
一个新加的 \(v\)
考虑维度当前加过的次数,\(dp(i,j)\) 表示走到 \(i\) 共用了 \(j\) 次 \(+v\) 操作的答案,对于上面三种情况分别有转移
-
\(dp(i+1,j)\leftarrow dp(i,j)\times a_i\)
-
\(dp(i+1,j)\leftarrow dp(i,j)\times j\times v\)
-
\(dp(i+1,j+1)\leftarrow dp(i,j)\times (i+1)\times (m-j)\times v\)
答案就是 \(\sum\frac{dp(n,i)}{n^i}\)。
2164E
我是口胡战神。
考虑答案的下界是 \(\sum w\),下界能取到相当于欧拉回路,取不到只需要管奇度点,那我每次就从一个奇度点跳到另一个奇度点并且一定跳,按照编号建 Kruscal 重构树,那我 \(u\) 跳到 \(v\) 相当于 \(rt\) 到 \(LCA(u,v)\) 的路径上的边权最小值,这玩意是相对于 \(dep\) 递减的所以直接贪心。
1513E(2300)
一些简单的观察是:最后一定调成平均数,如果平均值不是整数那一定不合法,并且操作的时候源点只可能是大于平均值的数,汇点只可能是小于平均值的数,等于平均值的数一动不动,如果小于平均值的数的个数小于等于 1 或者大于平均值的个数小于等于一那所有排列都是合法的,可重集计数即可。
这道题唯一的难点是 \(|i-j|\) 的限制,如果没有绝对值那所有排列就都是可行的。有这样的限制发现合法的排列一定满足要么源点都在汇点前面要么汇点都在源点前面,源点汇点分开计数乘起来再乘 \(2\dbinom{n}{c_{avg}}\) 就行了。
660E(2300)
怎么连着两个 *2300 的绿啊。
一般考虑的方向要么是值域要么是序列,但是这道题这两个都没法搞,这也是这道题最厉害的地方,他直接维护子序列这个东西。我们考虑一个长度为 \(i\) 的子序列 \(p_1,p_2,\dots,p_i\),值分别为 \(v_1,v_2,\dots,v_i\),想让这个子序列对答案产生贡献我直接规定 \([1,p_1-1]\) 里面没有 \(v_1\),\([p_{i-1}+1,p_{i}-1]\) 里面没有 \(v_i\),\(p_i\) 往后随便填。列一下式子就是
其中 \(j=p_i\)。用 \(i-1,j-1\) 代替 \(i,j\),交换 \(i,j\) 的顺序,有
然后最后那一块可以用二项式定理搞成
然后就做完了。

浙公网安备 33010602011771号