LG 題解 CF1545B AquaMoon and Chess
阿新 • • 發佈:2021-10-28
Solution
你拿到這個題後開始手模它這個操作。
你發現,對於一個 11
移動的時候就相當於整體左移或者右移。
我們假設讓它右移,如果它右邊是一個 0
,那麼它右移就相當於和這個 0
交換位置。如果它右邊是一個 1
,實際並不能右移,但也可以看做它和這個 1
交換了一下位置。
那不難看出,和 0
交換位置時會產生新的狀態,和 1
交換位置時並不會產生新的狀態。
也不難看出,每一組 11
在整個序列中都是可以自由移動的。那麼我們不妨將每個 11
都劃分成一個整體,對於那些單獨的 1
就直接扔掉。
那麼對於剩下的 11
和 0
,顯然可以隨便安排他們的位置。
設有 \(x\) 個 11
0
,總排列數位 \((x+y)!\),因為有重複狀態所以再除以 \(x! y!\),也就是說答案為 \(\binom{x+y}{x}\)。
直接預處理一個階乘和逆元就可以 \(\mathcal O(1)\) 計算了。
至於 \(x\) 和 \(y\) 從原串中暴力找就可以。
Code
/* Work by: Suzt_ilymtics Problem: 不知名屑題 Knowledge: 垃圾演算法 Time: O(能過) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define int long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 2e5+50; const int INF = 1e9+7; const int mod = 998244353; int T, n; int fac[MAXN], inv[MAXN]; char s[MAXN]; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } void Init() { int M = 200000; fac[0] = fac[1] = inv[0] = inv[1] = 1; for(int i = 2; i <= M; ++i) { fac[i] = fac[i - 1] * i % mod; inv[i] = (mod - mod / i) * inv[mod % i] % mod; } for(int i = 2; i <= M; ++i) { inv[i] = inv[i - 1] * inv[i] % mod; } } int C(int n, int m) { return fac[n] * inv[m] % mod * inv[n - m] % mod; } signed main() { Init(); T = read(); while(T--) { n = read(); cin >> s + 1; int y = 0, x = 0; for(int i = 1; i <= n; ++i) if(s[i] == '0') y++; for(int i = 2; i <= n; ++i) { if(s[i] == '1' && s[i - 1] == '1') { x++, s[i] = s[i - 1] = '0'; } } printf("%lld\n", C(x + y, x)); } return 0; }