题解 【AT3950 [AGC022E] Median Replace】

\(\large\mathcal{Description}\)

定义一个长度为奇数 \(n\)\(01\) 串为美丽的,当且仅当每次将连续 \(3\) 个位替换为它们的中位数 \(\dfrac{n-1}2\) 次后,这个串变成一个字符 \(1\).

现在给定由 \(0, 1, ?\) 三种字符组成的字符串 \(S\),求:将每个问号替换为 \(0/1\) 后,得到一个美丽的字符串的方案数,答案对 \(10^9+7\) 取模。

\(1 \le n \le 3\times 10^5\).

\(\large\mathcal{Solution}\)

如果我们已经将所有 \(?\) 填好了,如何判断得到的 \(S\) 是否是美丽的?

由于操作是“将连续 \(3\) 个位替换为它们的中位数”,即:将 \(000\) 变为 \(0\), 将连续的 \(01\)\(10\) 删掉,我们考虑维护一个栈。

我们从左到右加入每个字符,记当前栈顶为 \(c\),加入的字符为 \(k\).

  • \(c = 0,\ k = 0:\) 若当前栈中有 \(3\)\(0\),可将它们合并为 \(1\)\(0\).
  • \(c = 0,\ k = 1:\) 删去当前的 \(1\) 以及栈顶的 \(0\).
  • \(c = 1,\ k = 0:\) 正常加入当前 \(0\).
  • \(c = 1,\ k = 1:\) 若栈中 \(1\) 的个数 \(\ge 2\), 可忽略当前新加入的 \(1\)

则维护后的栈必定满足两个性质:

  • \(0, 1\) 的个数不超过 \(2\).
  • 必定是若干个 \(1\) 接着若干个 \(0\)

回到原题,我们设计动态规划状态为 \(f_{i, j, k}\) 表示做到第 \(i\) 位,当前栈中有 \(j\)\(1\), 有 \(k\)\(0\) 的方案数,按照上面的过程转移即可。

最后答案即使 \(f_{n, 2, 0} + f_{n, 2, 1} + f_{n, 2, 2} + f_{n, 1, 0}.\)

\(\large\mathcal{Code}\)

#include <bits/stdc++.h>
#define reg register

using namespace std;

typedef long long LL;
const int N = 300010, p = 1000000007;

int n;
char ch[N];
LL f[N][3][3];

int main()
{
	scanf("%s", ch + 1); n = strlen(ch + 1);
	
	f[0][0][0] = 1;
	
	for (reg int i = 0; i < n; ++ i)
	    for (reg int j = 0; j < 3; ++ j)
	        for (reg int k = 0; k < 3; ++ k)
	        {
	        	if (ch[i + 1] != ‘0‘)
	        	{
	        		if (k) f[i + 1][j][k - 1] = (f[i + 1][j][k - 1] + f[i][j][k]) % p;
	        		else f[i + 1][min(j + 1, 2)][k] = (f[i + 1][min(j + 1, 2)][k] + f[i][j][k]) % p;
				}
				
				if (ch[i + 1] != ‘1‘)
				{
					if (k == 2) f[i + 1][j][1] = (f[i + 1][j][1] + f[i][j][k]) % p;
					else f[i + 1][j][k + 1] = (f[i + 1][j][k + 1] + f[i][j][k]) % p;
				}
			}
	
	printf("%d\n", (f[n][2][0] + f[n][2][1] + f[n][2][2] + f[n][1][0]) % p);
	return 0;
}

题解 【AT3950 [AGC022E] Median Replace】

上一篇:ETCD部署


下一篇:docker 拉取镜像