題解 【AT3950 [AGC022E] Median Replace】
阿新 • • 發佈:2021-08-01
\(\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\)
則維護後的棧必定滿足兩個性質:
- \(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; }