1. 程式人生 > 其它 >#codeforces 1546D - AquaMoon and Chess 題解

#codeforces 1546D - AquaMoon and Chess 題解

原題連結``
思路:
顯然如果有連續偶數個“1”,那麼這些一可以拆成若干組“11”自由移動。
因此有了思考方向,用捆綁法,以2個“1”一組。
那麼,如果有連續奇數個“1”該怎麼辦?
經過操作觀察,我們發現,多出來的“1”我們其不需要理它,去掉一個“1”將剩下的偶數個“1”按上述分組,將這些組和0排列後,原來多處來的一個“1”是唯一確定的
因此。我們記錄0的個數cnt0,記錄組數g
答案為從cnt0 + g 個數中 取出g個數的方案數
程式碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 998244353;
ll t;
ll n;
ll cnt0;
ll cnt1;
ll g;
ll ans;
string s;
ll f[100010];
ll fin[100010];
ll qpow(ll x, ll y) {
	ll ret = 1ll;
	while (y) {
		if (y & 1) ret = (ret * x) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ret % mod;
}
ll inv(ll x) {
	return qpow(x, mod - 2);
}
void init() {
	f[0] = fin[0] = 1ll;
	for (ll i = 1; i <= 100000; i++) {
		f[i] = (i * f[i - 1]) % mod;
		fin[i] = (fin[i - 1] * inv(i)) % mod;
	}
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	init();
	cin >> t;
	while (t--) {
		cnt0 = cnt1 = g = 0; 
		cin >> n;
		cin >> s;
		for (int i = 0; i < s.length(); i++) {
			if (s[i] == '1') {
				if (i == s.length() - 1) {
					cnt1 ++;
					g += cnt1 / 2;
				}
				else {
					cnt1 ++;
				}
			}
			else {
				cnt0 ++;
				g += cnt1 / 2;
				cnt1 = 0;
			}
		}
		ans = ((f[cnt0 + g] * fin[g])  % mod * fin[cnt0]) % mod;
		cout << ans << "\n";
	}
	return 0;
}