先考虑全体为 000 和 111 的数。想要最后变为 000 就要抵消掉所有的 111。从小考虑:
111:一次操作变为 000。
101010:10→−19→翻转1→−1010 \xrightarrow{-1} 9 \xrightarrow{\text{翻转}} 1 \xrightarrow{-1} 010−19翻转1−10。
100100100:100→−199→翻转11→10→…100 \xrightarrow{-1} 99 \xrightarrow{\text{翻转}} 11 \rightarrow 10 \rightarrow \dots100−199翻转11→10→…。
可以发现当 10…010\ldots010…0 减 111 后变为 9…99\ldots99…9,通过翻转就变成了 1…11\ldots11…1。
也就是说想抵消第 nnn 位(从右往左)的 111,相当于抵消第 111 到第 n−1n-1n−1 位上的 111 再加 222 步。由此得出转移。
dp[1] = 1;
int cnt = 1; // 把第 1 到第 i-1 位上的 1 抵消所耗次数
for (int i = 2; i <= 200004; i++) {
dp[i] = (cnt + 2) % 1000000007;
(cnt += dp[i]) %= 1000000007;
}
对于每一次询问,先将非全体为 000 和 111 的数转成 010101,然后用初始化完的数据去累加。
#include <bits/stdc++.h>
using namespace std;
int dp[200004]; // 把第 i 位(从右往左)的 1 抵消所耗次数
int t;
int a[200004];
signed main() {
dp[1] = 1;
int cnt = 1; // 把第 1 到第 i-1 位上的 1 抵消所耗次数
for (int i = 2; i <= 200004; i++) {
dp[i] = (cnt + 2) % 1000000007;
(cnt += dp[i]) %= 1000000007;
}
cin >> t;
while (t--) {
string s;
cin >> s;
for (int i = 0; i < s.size(); i++) a[i + 1] = s[i] - '0';
int n = s.size();
int ans = 0;
for (int i = 1; i <= n; i++) {
if (a[i] != 0 and a[i] != 1) {
a[i] = a[i] % 2;
ans = 1; // 先把数字转成 01,花费 1 次
}
}
for (int i = n; i >= 1; i--) { // 从右往左
(ans += (a[i] ? dp[n - i + 1] : 0)) %= 1000000007;
}
cout << ans << "\n";
}
return 0;
}
洛谷链接:
https://www.luogu.com.cn/article/9hwxcho3
387

被折叠的 条评论
为什么被折叠?



