dp 好题
AGC002F Leftmost Ball
给你 \(n\) 种颜色的球,每个球有 \(k\) 个,把这 \(n\times k\) 个球排成一排,把每一种颜色的最左边出现的球涂成白色(初始球不包含白色),求有多少种不同的颜色序列,答案对 \(10^9+7\) 取模。
将这 \(n\times k\) 个球看成 \(n\) 个白球和 \(n\times k - n\) 个其他颜色的球,由于白球是每种颜色的第一个,所以要保证对于每个位置前缀白球个数均大于等于其他颜色种类数。
设 \(f_{i,j}\) 表示已经放了 \(i\) 个白球和 \(j\) 个其他球的方案数 \((i\ge j)\)。
转移时考虑最后一个放的什么:
-
白球:\(f_{i-1,j}\)
-
新的颜色:\(f_{i,j-1}\times (n-j+1) \times \binom{n\times k-i-(j-1)\times(k-1)-1}{k-2}\)
这里,我们将每个颜色的球的贡献全算上,在剩下 \(n-j+1\) 个颜色中任选一个放在 \(i\),然后该颜色还剩 \(k-2\) 个球,放在后面 \(n\times k-i-(j-1)\times(k-1)-1\) 个空中。
AGC001E BBQ Hard
有 \(n\) 个数对 \((a_i,b_i)\),求出
\[\sum_{i=1}^{n}\sum_{j=i + 1}^{n}{a_i+b_i+a_j+b_j \choose a_i+a_j} \]答案对 \(10^9+7\) 取模
\(2\le n \le 200000,1\le a_i,b_i\le 2000\)
观察到 \(n\) 很大而值域很小,考虑对值域进行操作。
\(\binom{a_i+b_i+a_j+b_j}{a_i+a_j}\) 这个形式其实就是在坐标系上从 \((-a_i,-b_i)\) 只能向上或向右走,走到 \((a_j,b_j)\) 的方案数,所以我们就是要求任意两点间路径方案数的和。
考虑如何把复杂度降下来,如果能对每个点算其他所有点到它的路径方案数,就可以 \(O(n)\) 枚举了。
设 \(f_{i,j}\) 表示所有关键点到 \((i,j)\) 的方案数之和,转移也很简单 \(f_{i,j} = f_{i-1,j}+f_{i,j-1}\),初值 \(f_{-a_i,-b_i}=1\)。
但题目要求 \(i<j\),所以减掉 \(\binom{a_i+b_i+a_i+b_i}{a_i+a_i}\) 后除以 \(2\) 即可。
ARC074C RGB Sequence
有一个序列 \(\left\{a_{i}\right\}\),要给序列中的每个元素一种颜色:红/绿/蓝。有 \(M\) 条限制 \((l,r,x)\),表示格子 \([l,r]\) 中颜色的种数要恰好为 \(x\),问可行的方案数,答案对 \(10^9+7\) 取模。
\(1\le n,m\le 3000\)
观察到只有三种颜色,所以可以记录下每个颜色最后出现的位置。
设 \(f_{i,j,k}\) 表示考虑到第 \(i\) 个数,另外两种颜色最后出现在 \(j\) 和 \(k\),钦定 \(j>k\),转移很显然
- \(f_{i+1,j,k}+=f_{i,j,k}\)
- \(f_{i+1,i,k}+=f_{i,j,k}\)
- \(f_{i+1,i,j}+=f_{i,j,k}\)
对于限制,挂到 \(r\) 上,在每次向后转移前更新一遍,由于已经知道了另外两个颜色最后的位置,就可以得到 \([l,r]\) 中的颜色数了,将不合法的改为 \(0\) 即可。
P2501 [HAOI2006]数字序列
给定一个长度为 \(n\) 的序列 a,求最少需要改变多少个数才能让 \(a\) 单调严格上升,同时每个数改变的绝对值之和最小是多少。
\(1\le n\le 3.5\times 10^4,1\le a_i\le 10^5\)
第一问
考虑保留最多的数,对于 \(i<j\),如果 \(a_i,a_j\) 可以保留,那么至少 \(a_j-a_i\ge j-i\),也就是 \(a_i-i\le a_j-j\)。
设 \(b_i=a_i-i\),其最长不下降子序列即为答案。
第二问
在第一问的基础上,找到两个在 \(b\) 的最长不下降子序列上相邻的点 \(i,j\),那么 \(\forall k \in (i,j),b_k<a_i 或 b_k>b_j\),我们要把中间的这部分改成合法的,不难想到最优情况下一定是前一部分改成 \(b_i\),后一部分改成 \(b_j\),这个中间点直接枚举是可以过的(
同时 dp 记录一下 \(f_i\) 表示 \([1,i]\) 都合法的最小代价即可。
P3943 星空
有一串长为 \(n\) 的灯泡,其中有 \(k\) 个灯是关的。给定 \(m\) 个可以翻转的长度,也就是每次可以翻转这 \(m\) 个长度之一的灯泡,求最少操作多少次可以将所有灯泡打开。
\(n \le 40000, m\le 64,k\le 8\)
将灯的开关状态看为 \(0/1\),每次操作都是让一段区间异或 \(1\)。这种区间操作可以利用差分,这样每次操作修改两个位置。
由于最多有 \(8\) 个灯是关着的,所以差分数组中最多有 \(16\) 个 \(1\),我们要把这些 \(1\) 都改成 \(0\),预处理出相邻两个之间的距离状压 dp 即可。
具体来说,先 bfs 求出想改变两个相距 \(x\) 的位置的状态最少需要操作几次,然后转移时枚举最后修改的两个位置。
P3830 [SHOI2012]随机树
\(2\le n\le 100\)
第一问
比较简单,设 \(f_i\) 表示 \(i\) 个点的树的叶节点平均深度的期望,转移
第二问
设 \(f_{i,j}\) 表示有 \(i\) 个叶子,深度 \(\ge j\) 的概率,转移时枚举左儿子叶子数
只要有一边深度 \(\ge j-1\) 就行了,减掉两边都 \(\ge j-1\) 的,至于左子树的大小 \(k\),取 \([1,i-1]\) 的概率都是相等的,所以直接除以 \(i-1\)。
P3058 [USACO12NOV]Balanced Cow Breeds G/S
给一个只有左右括号的字符串,然后用
H
、G
两种字符来标记这个序列,所有标记H
的括号可以组成一个正确的括号序列,所有G
标记的括号也组成一个正确的括号序列,然后输出这种标记方案的总数 \(\bmod 2012\) 的值。
由于有两个标记,考虑分开记录,设 \(f_{i,j,k}\) 表示到第 \(i\) 个字符,打 H
标记的剩下 \(j\) 个 "(",打 G
标记的剩下 \(k\) 个 "(" 的方案数。
转移时判断是什么括号,然后分讨打 H
或 G
标记
- 如果是 "("
H
: \(f_{i,j,k}+=f_{i-1,j-1,k}\)G
: \(f_{i,j,k}+=f_{i-1,j,k-1}\)
- 如果是 ")"
H
: \(f_{i,j,k}+=f_{i-1,j+1,k}\)G
: \(f_{i,j,k}+=f_{i-1,j,k+1}\)
最后答案为 \(f_{n,0,0}\),第一维可以滚动。
P4798 [CEOI2015 Day1]卡尔文球锦标赛
数位 dp
如果使用 dfs 写法,记忆化数组空间需要 \(O(n^2)\),记录当前在第几位,以及前面填的数中最大是多少,但很可惜空间开不下,放个代码
Code
int dfs(int cur, bool lim, int pre)
{
if(cur == n + 1) return 1;
if(!lim && ~f[cur][pre]) return f[cur][pre];
int res = 0, up = lim ? a[cur] : pre + 1;
for(int i = 1; i <= up; i++)
res = add(res + dfs(cur + 1, lim & (i == up), max(pre, i)));
if(!lim) f[cur][pre] = res;
return res;
}
考虑递推,用时间换空间,设 \(f_{i,j,0/1}\) 表示前 \(i\) 个数,最大值为 \(j\),是否顶着上界的方案数。
转移时从 \(f_{i,j,0/1}\) 向后转移,讨论最后一个填什么
第一维可以滚动。
AT2087 Friction
给定一个 \(n\times m\) 的矩阵,矩阵上每个格子都有一个小写字母表示颜色,每次操作可以选择一列向下推一格,然后最下面的格子会消失,操作一次的代价为操作前这一列中与旁边格子颜色相同的对数。
求将整个矩阵全消掉所需要的最小代价。
\(1\le n \le 300,2\le m\le 300\)
首先有个性质,任意相邻的两列的代价相互独立,也就是相邻两列的贡献可以单独算。
证明:考虑消掉三列的代价,相邻两列间相对操作顺序是不受第三列的影响的,并且两列如果不相邻是不会产生贡献的,所以代价可以单独计算。
接下来就是简单 dp 了,设 \(f_{i,j}\) 表示第一列还剩 \(i\) 个格子,第二列还剩 \(j\) 个格子消完的代价。
其中 \(w(i,j)\) 表示这个状态下的代价,可以递推出来,假设当前在算第 \(x\) 列和第 \(y\) 列的贡献
于是就可以 \(O(n^2m)\) dp 了。
CF327E Axis Walking
给你一个长度为 \(n\ (1\le n\le 24)\) 的正整数序列 \(S\),再有 \(k\ (0\le k\le 2)\) 个正整数。
求有多少种 \(S\) 的排列方式使得其前缀和不会成为那 \(k\) 个数里的任意一个。 答案对 \(10^9+7\) 取模。
看到 \(n\le 24\) 不难想到状压,设 \(f(S)\) 表示当前已经确定的数为 \(S\),转移时枚举一个没有在 \(S\) 中的数 \(i\),并判断 \(sum(S)+a_i\) 是否合法。
这样复杂度是 \(O(2^nn)\),理论上 3s 是能过的,但是由于这是远古 CF 题,时限减半没能卡过去,考虑换一种转移方式。
对于一个状态 \(S\),我们可以枚举最后一个数是多少,然后从前面的状态转移过来,这个可以用 \(lowbit\) 优化,常数极小,可以通过。
P3451 [POI2007]ATR-Tourist Attractions
给出一张有 \(n\) 个点 \(m\) 条边的无向图,每条边有边权。
你需要找一条从 \(1\) 到 \(n\) 的最短路径,并且这条路径在满足给出的 \(g\) 个限制的情况下可以在所有编号从 \(2\) 到 \(k+1\) 的点上停留。
每个限制条件形如 \(r_i, s_i\),表示停留在 \(s_i\) 之前必须先在 \(r_i\) 停留过。
注意停留不等于经过。
\(2\le n\le2\times10^4\)
\(1\le m\le2\times10^5\)
\(0\le k\le\min(20, n-2)\)
\(2\le r_i, s_i\le k+1, r_i\not=s_i\)
观察到 \(k\) 很小,依然可以状压,所以思路就很清晰了
先对这 \(k\) 个点跑一遍最短路,设 \(f_{S,i}\) 表示从 \(1\) 出发,已经在 \(S\) 中的点停留过,最后待在 \(i\) 的最短路,转移时枚举不在 \(S\) 中的 \(j\),要先判断能否在 \(j\) 停留,这个对每个点存一个需要的状态即可。
这样做空间复杂度是 \(O(2^nn)\) 的,大概是 80MB 左右,并不能过,需要卡空间。
其实差的并不多,只需要把 \(i\) 在 \(S\) 中去掉,也就是当前在 \(i\) 节点,那么状态里就不要存是否有 \(i\),这样空间就是 \(O(2^{n-1}n)\) 了。
CF1067D Computer Game
有 \(n\) 个游戏,每个游戏有收益 \(a_i\),升级后的收益 \(b_i\),每次成功概率 \(p_i\)。每秒可以玩一个游戏,如果成功则得到当前收益,并且可以升级任意某个游戏。求 \(t\) 秒后的期望收益的最大值。
\(n\le 1e5,t\le 10^{10},a<b\)
不难发现,我们要想办法将 \(b_ip_i\) 最大的那个升级,然后后面一直玩这个游戏。
设计一个 dp,\(f_t\) 表示还剩 \(t\) 秒时期望收益最大值
其中 \(mx\) 是 \(b_ip_i\) 的最大值,然后里面的可以斜率优化,将 \(p_i\) 看作 \(k\),\(p_ia_i\) 看作 \(b\),维护一个直线的凸包即可。
注意到 \((t-1)mx-f_{t-1}\) 是单调不降的,因为 \(mx\) 已经是最大的,\(f_t\) 的增量不可能大于 \(mx\)。
所以可以直接扫一遍凸包上的直线,二分可行的转移区间,矩阵快速幂优化,这样做是 \(O(n\log^2n)\) 的。
因为已经确定了决策点,可以直接矩阵快速幂
把二分改成矩阵倍增即可做到 \(O(n\log n)\)。
维护凸包、倍增找可行转移区间时都是判断直线交点的横坐标。
T249441 【愚蠢的戴夫】豌豆射手
在长为 \(m\) 的草坪上放 \(n\) 个豌豆射手,每个豌豆射手有一个攻击半径 \(r_i\),求有多少种放置方案使豌豆射手不互相攻击。答案对 \(10^9+7\) 取模。
\(n\le 40,m\le10^5,1\le r_i\le 40,\sum r_i\le m\)
观察到 \(d\) 很大,而 \(\sum{r_i}\) 却只有 \(1600\),考虑先尽量让豌豆射手挨着放,这样后面会空出来一段,然后再把后面的空位分配到前面。
相邻的豌豆射手间的距离是 \(\max(r_i,r_j)\),所以我们按 \(r_i\) 排序,从小到大放,就可以知道每个豌豆射手的贡献了。
令 \(f_{i,j,k}\) 表示放了前 \(i\) 个豌豆射手,形成了 \(j\) 个连续段,共占了 \(k\) 个草坪的方案数。
转移时对 \(i+1\) 进行分类讨论
-
单独形成一段,有 \(j+1\) 段空区间,多占了一个草坪
\(f_{i+1,j+1,k+1}+=f_{i,j,k}\times (j+1)\)
-
与前面某一段连起来,有 \(j\) 段,每段的两端都可以,连起来多占的长度一定为 \(r_{i+1}\)
\(f_{i+1,j,k+r_{i+1}}+=f_{i,j,k}\times 2j\)
-
连接了两段,有 \(j-1\) 个区间,多占的长度为 \(2r_{i+1}-1\),因为自己被算了两遍
\(f_{i+1,j-1,k+2r_{i+1}-1}+=f_{i,j,k}\times (j-1)\)
然后考虑如何计算后面的空位分配给前面有多少种,其实就是插板法,前面共有 \(n\) 个豌豆射手,每个前面都可以加空位,设第 \(i\) 个豌豆射手前面加了 \(a_i\) 个,那么 \(\sum a_i=n-s\),其中 \(s\) 为已经占的草坪,方案数就是 \(\binom {n-s+n}{n}\)。
P6944 [ICPC2018 WF]Gem Island
有 \(n\) 个人,最开始每个人手中有 \(1\) 颗绿宝石,每天晚上,会随机选一个绿宝石分裂为两个。
求 \(d\) 个晚上后绿宝石数量最多的 \(r\) 个人的绿宝石数和的期望值。
\(1\le n,d\le 500,1\le r\le n\)
设最后每个人的宝石的序列为 \(\{a_i\}\),可以证明每种情况是等概率的(可以用归纳法)。
那么我们要求的就是所有序列中前 \(r\) 大的和,考虑 dp
设 \(f_{i,j}\) 表示 \(a_1+a_2+\cdots+a_i=j\) 的所有序列中前 \(r\) 大的和,这里 \(a_i\) 为第 \(i\) 个人多了几个宝石,所有的和即为 \(f_{n,d}+r\)。
AGC013D Piling Up
一开始有 \(n\) 个颜色为黑白的球,但不知道黑白色分别有多少,\(m\) 次操作,每次先拿出一个球,再放入黑白球各一个,再拿出一个球,最后拿出的球按顺序排列会形成一个颜色序列,求颜色序列有多少种。答案对 \(10^9+7\) 取模。
\(n,m\le 3000\)
操作共有四种:
- 取白,放黑白,取白
- 取白,放黑白,取黑
- 取黑,放黑白,取白
- 取黑,放黑白,取黑
法向我们可以知道每次操作白球个数如何变化,令 \(f_{i,j}\) 表示操作 \(i\) 次,有 \(j\) 个白球的方案数。
但是最后是把拿出的球按顺序排列形成一个颜色序列,会出现白球个数不同但取球方案相同的,这样会算重,考虑如何去重。
我们将白球个数变化曲线放到一个平面上,对于平移后可以重合的都是相同的方案,所以我们只计算那些碰到过 \(x\) 轴的,就可以不重不漏了。
那么状态为 \(f_{i,j,0/1}\),最后的 \(0/1\) 表示是否碰到过 \(x\) 轴,转移也比较好写。
Code
for(int i = 0; i <= n; i++) f[0][i][!i] = 1;
for(int i = 0; i < m; i++)
for(int j = 0; j <= n; j++)
{
if(j - 1 >= 0) // 第一次取白
{
// 第二次取白
if(j == 1) f[i + 1][j - 1][1] = add(f[i + 1][j - 1][1] + f[i][j][0]);
else f[i + 1][j - 1][0] = add(f[i + 1][j - 1][0] + f[i][j][0]);
f[i + 1][j - 1][1] = add(f[i + 1][j - 1][1] + f[i][j][1]);
// 第二次取黑
if(j == 1) f[i + 1][j][1] = add(f[i + 1][j][1] + f[i][j][0]);
else f[i + 1][j][0] = add(f[i + 1][j][0] + f[i][j][0]);
f[i + 1][j][1] = add(f[i + 1][j][1] + f[i][j][1]);
}
if(j + 1 <= n) // 第一次取黑
{
// 第二次取白
f[i + 1][j][0] = add(f[i + 1][j][0] + f[i][j][0]);
f[i + 1][j][1] = add(f[i + 1][j][1] + f[i][j][1]);
// 第二次取黑
f[i + 1][j + 1][0] = add(f[i + 1][j + 1][0] + f[i][j][0]);
f[i + 1][j + 1][1] = add(f[i + 1][j + 1][1] + f[i][j][1]);
}
}
P4456 [CQOI2018]交错序列
我们称一个仅由 \(0,1\) 构成的序列为”交错序列“,当且仅当序列中没有相邻的 \(1\) (可以有相邻的 \(0\))。
对于一个长度为 \(n\) 的交错序列,统计其中 \(0\) 和 \(1\) 出现的次数,分别记为 \(x\) 和 \(y\)。给定参数 \(a,b\),定义一个交错序列的特征值为 \(x^ay^b\)。
求所有长度为 \(n\) 的交错序列的特征值的和,对 \(m\) 取模。
\(1\le n \le 10^7,0\le a,b\le 45,m\le 10^8\),且 \(m\) 为质数。
先将式子化简一下,因为 \(x+y=n\)
所以我们要求对于 \(i\in [0,a+b]\) 求出所有合法序列中 \(y^i\) 的和。
设 \(f_{i,j,0/1}\) 表示前 \(i\) 位,最后一位为 \(0/1\),\(y^j\) 的和。
考虑下一位填什么,若填 \(0\),那么可以从 \(0/1\) 转移,若填 \(1\),那么只能从 \(0\) 转移。
填 \(0\) 的话直接加起来就行了,考虑填 \(1\) 如何转移,\(y\) 会变成 \(y+1\),将 \((y+1)^j\) 展开
然后直接矩乘就行了,\(0/1\) 的话就开两倍。
CF797F Mice and Holes
\(f_{i,j}\) 表示前 \(i\) 个老鼠进前 \(j\) 个洞的最小距离,转移时枚举后面有多少老鼠进第 \(j\) 个洞,单调队列优化。
P1399 [NOI2013] 快餐店
基环树,从快餐店出发到所有点的最短路一定有一条环上的边没有经过,枚举一条环上的边删掉,求树的直径的最小值即可。
AGC009D Uninity
原题转化为,给树上每个点赋一个权值,满足任意两个相同权值的点之间存在比这个权值大的点,求权值的最大值最小是多少。
贪心从叶子往上取每个点能取的最小值,用 bitset 记录不能选的集合。
P4285 [SHOI2008]汉诺塔
\(g_{i,j}\) 表示在第 \(j\) 根柱子上有第 \(i\) 个盘子,到最终状态会到哪根柱子上,初值 \(g_{1,j}\) 由输入得到。
\(f_{i,j}\) 表示把第 \(i\) 个盘子从第 \(j\) 根柱子上移动到第 \(g_{i,j}\) 根柱子上需要几步。
转移时大力分类讨论。
CF704C Black Widow
连边,每个点的度数 \(\le 2\),会形成若干环和链,对于不同的连通分量,可以分别计算出异或值为 \(0/1\) 的方案数。
考虑链的情况,设 \(f_{i,j,k}\) 表示前 \(i\) 个点,第 \(i\) 个点值为 \(j\),已知表达式值的异或和为 \(k\) 的方案数,转移时枚举 \(i-1\) 的值即可。
对于环的情况,先固定一个点,然后从这里破环为链,最后答案取这个点固定的值。
P4564 [CTSC2018]假面
对于「锁定」技能,考虑每个位置分开算,\(f_{i,j}\) 表示单位 \(i\) 还有 \(j\) 点生命值的概率,最后对于单位 \(i\) 答案为 \(\sum j\times f_{i,j}\)。
对于「结界」技能,考虑分开计算命中单位 \(i\) 的概率,枚举除 \(i\) 以外存活的单位数 \(j\),记这个概率为 \(p_j\),设当前 \(i\) 存活的概率为 \(a_i\),那么答案为
设 \(g_k\) 表示存活 \(k\) 个单位的概率,\(O(n^2)\) dp 很平凡,但是要对每个单位 dp 一遍,无法接受。
我们需要的是除 \(i\) 以外所有单位的概率,那么我们可以先求出所有单位的,然后把 \(i\) 删掉,写出转移矩阵不难做到 \(O(n)\)。
总复杂度为 \(O(Cn^2+Qm)\)。
UOJ140 被粉碎的数字
数位 dp,\(dp_{i,j,p,q}\) 表示从低到高前 \(i\) 位,此时 \(f(x\bmod 10^i)-f(k\times x\bmod 10^i)=j\),进位为 \(p\),\(q\) 表示 \(x\) 是否大于 \(R\)。
转移时枚举第 \(i+1\) 位为 \(d\)
P7093 [CERC2014]Can't stop playing
如果存在,那么最终的序列一定是单峰的,并且和为 \(2^k\),记 \(L\) 为峰左边的和,\(R\) 为峰及其右边的和,放入第 \(i\) 个数后和为 \(S_i\)。
设 \(f_{i,L}\) 表示放入第 \(i\) 个数后能否达到左边和为 \(L\),右边和为 \(S_i-L\) 的状态,这里保证 \(L<\dfrac {S_i} 2\)。
转移时分类讨论即可,特殊地,当序列单调递增(减)时,两边都可以加入。输出方案就令 \(f_{i,L}\) 为从 \(L'\) 转移过来的。
P2476 [SCOI2008]着色方案
观察到每种颜色能涂的木块数很少,并且两种能涂的木块数相同的颜色是完全等价的,考虑记录能涂 \(i\) 个木块的颜色有多少,还需要记录上一个木块的颜色(这里也不需要真的记颜色,只需要知道能涂的木块数),状态数 \(15^5\times 6=4556250\)。
转移时枚举颜色能涂几个木块,如果上一个涂的能涂 \(k\) 块的,那么这个涂能涂 \(k-1\) 块的颜色数需要 \(-1\),记忆化搜索优化。
P3648 [APIO2014] 序列分割
不难发现,切割的顺序对答案没有影响,那么直接 dp,令 \(f_{i,j}\) 表示序列前 \(i\) 项,切了 \(j\) 次的最大得分。
将两维交换一下,并把第一维滚动数组优化掉,然后斜率优化即可。
P2470 [SCOI2007]压缩
方便起见,我们约定每一段都由 M
开头,这样最后答案 \(-1\) 即可。
由于不能压缩已经压缩过的字符串,所以我们需要知道某个子串是否压缩过。记 \(s[l,r]\) 表示字符串 \(s\) 中 \([l,r]\) 组成的子串,令 \(f_{i,j}\) 表示 \(s[l,r]\) 压缩后除了开头的 M
外没有 M
的最短长度,\(g_{i,j}\) 表示 \(s[l,r]\) 压缩后由多个 M
的最短长度。
AGC026E Synchronized Subsequence
先将原序列分段,每段内 \((a,b)\) 都完全匹配并且长度尽量小,这样每段可以单独处理然后单调栈求字典序最大的串。不难发现每一段内匹配的 \((a,b)\) 的相对位置是相同的。
发现串里只有 \(a,b\),所以要尽量让 \(b\) 靠前,进行分类讨论:
- 当该段内第一个为 \(a\) 时,由于每对 \((a,b)\) 的相对位置都是 \(a\) 在前 \(b\) 在后,如果保留了 \(a\),那么下一个保留和这个 \(a\) 匹配的 \(b\) 是最优的,所以保留的串形如 \(abab\dots\),求最长的长度即可。
- 当该段内第一个为 \(b\) 时,相对位置为 \(b\) 在前 \(a\) 在后,这时候要找到极长的 \(bb...b\),并且有个贪心,就是找到极长连续的 \(b\) 后后面的都保留,因为 \(b\) 在前 \(a\) 在后,多保留一对会更优。
最后单调栈处理一下就行了。
CF441E Valera and Number
观察到操作次数非常少,就导致 \(+1\) 的影响不会很大,具体来说,只会影响后 \(8\) 位。
设 \(f_{i,s,j,k}\) 表示 \(i\) 次操作,后 \(8\) 位状态为 \(s\),第 \(9\) 位及前面连续 \(j\) 位都是相同的,第 \(9\) 位为 \(k\) 的概率。
转移时分讨 \(\times 2\) 和 \(+1\),注意一下进位即可。
最后统计答案枚举后 \(3\) 维。