AGC022E Median Replace
题意:给定长度为奇数的 01? 串,问多少种填法使得串可以变成
这种计数题可以先考虑怎么判定一个串是否可以变成
根据人类智慧,可以想到
观察发现:
-
; -
; -
; -
; -
; -
; -
一定合法。
第七条是非常显然的,只需证明前六条;而前六条性质从右到左同样非常显然,只需证明前六条的
引理:
证明:
考虑
-
,因为能变成 ,所以 中必有一个 。 -
。若 对应的是 ,则 都能变成 ,显然 能变成 。否则
对应变成 ,根据归纳法, 能变成 ,可以发现无论 , 也都能变成 。
引理证毕,下面开始证明。
-
合法,考虑 倒数第二步时的三个数对应原本的哪三段。-
,这表示因为 要能变成 ,所以 可以变成 。 -
,因为有一个 ,所以 都要能变成 。根据引理, 能变成 ,所以 一起能变出两个 一个 , 合法。 -
。如果 变成的是 ,则 都变成 , 可以变成 , 合法。否则
归纳法证明。
-
上面六条都可以类似证明,可自行练习。
另外这里可以偷个懒:
在证明了上面六条之后,我们可以建立一个这样的自动机:接受的信号类型只有
例如
例如
另外,代表 "11" 的结点是终止状态。
于是我们可以在自动机上 DP。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5, MOD = 1e9 + 7;
string s;
ll dp[N][8] = {{}};
int e[10][2];
ll ans = 0;
int main() {
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stdout);
cin >> s;
if (s.size() == 1) {
if (s == "1" || s == "?")
cout << 1 << endl;
else
cout << 0 << endl;
return 0;
}
e[1][0] = 2;
e[1][1] = 4;
e[2][1] = 1;
e[2][0] = 3;
e[3][0] = e[3][1] = 2;
e[4][0] = 5;
e[4][1] = 7;
e[5][0] = 6;
e[5][1] = 4;
e[6][0] = e[6][1] = 5;
dp[0][1] = 1;
for (int i = 0; i < s.size(); i++) {
for (int j = 1; j <= 6; j++) {
if (s[i] != '0')
dp[i + 1][e[j][1]] = (dp[i + 1][e[j][1]] + dp[i][j]) % MOD;
if (s[i] != '1')
dp[i + 1][e[j][0]] = (dp[i + 1][e[j][0]] + dp[i][j]) % MOD;
}
}
ans = dp[s.size()][4];
for (ll i = s.size() - 1, pw = 1; i >= 0; i--) {
ans = (ans + dp[i + 1][7] * pw % MOD) % MOD;
if (s[i] == '?')
pw = pw * 2 % MOD;
}
cout << ans << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!