CF2255B A Ribbon for Tomorrow
看到 \(01\) 串首先想到把连续相同的一段压缩成一个点,这是这种题常见的套路。
自己搓两组数据手玩一下,发现以下三点:
第一,黑白黑白交替的整体框架不会因为操作改变,就是说不会变成白黑白黑。
第二,单看一种颜色,发现每段的数量是可以随意地内部调配的,同时可以保证另一种颜色的段不受影响。说下具体方法:比如现在是相邻的三段黑白黑,那么可以先让白段自己完整交换一次,然后按数量需要交换两边的黑,最后再把白段完整地交换一次。
第三,根据第二点,黑子的方案数和白子的方案数是独立的。因此答案就是两个方案数乘起来。
会用到逆元,快速幂。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int MAXN = 1e6;
const int N = 2e6;
const int mod = 998244353;
int a[N];
char s[N];
int T, n, num1, num2, duan1, duan2;
ll frac[N];
ll quickmod(ll x, int y){
ll ret = 1;
while(y){
if(y & 1) ret = ret * x % mod;
x = x * x % mod;
y >>= 1;
}
return ret;
}
ll suan(ll k, ll r){
if(k <= 0) return 1; // no this number or only 1, then return 1
ll tmp = ((frac[k] * quickmod(frac[r], mod - 2)) % mod * quickmod(frac[k - r], mod - 2)) % mod;
return tmp;
}
void Main(){
num1 = num2 = duan1 = duan2 = 0;
cin >> n;
cin >> s;
F(i, 0, n - 1) a[i + 1] = s[i] - '0';
F(i, 1, n){
if(a[i] == 0) ++ num1;
else ++ num2;
if(i == 1){
if(a[i] == 0) ++ duan1;
else ++ duan2;
}
else if(a[i] != a[i - 1]){
if(a[i] == 0) ++ duan1;
else ++ duan2;
}
}
// F(i, 1, n) cout << a[i] << ' ';
// cout << '\n';
// cout << num1 << ' ' << duan1 << '\n';
// cout << num2 << ' ' << duan2 << '\n';
// cout << '\n';
ll res = suan(num1 - 1, duan1 - 1) * suan(num2 - 1, duan2 - 1) % mod;
cout << res << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
frac[0] = 1;
F(i, 1, MAXN) frac[i] = frac[i - 1] * i % mod;
// assert(frac[MAXN] * quickmod(frac[MAXN], mod - 2) % mod == 1);
cin >> T;
while(T --) Main();
return fflush(0), 0;
}

浙公网安备 33010602011771号