CF2255B
CF2255B
注意到对于任意次翻转操作来说 , 0/1 数量不变 , 0/1 的连在一起的块的数量是不变的
证明:
0/1 数量不变很正常,只需证明 0/1 的联通块数量不变即可
因为 \(s_r = s_l\) 的时候才会翻转,那么外部的联通块数量不变,内层也不变
$\Box $
再次注意到如果两个字符串的 0/1 数量相同, 联通块数量相同,则可以互相转化
证明:
考虑到字符串的联通块的形式是 0-1 交替的,则对于我们要想得到的字符串 \(t\) 来说,
每一个联通块中的的数量和对应的字符串 \(s\) 的联通块中的数量可以通过后方的一个同颜色的联通块的前半部分交换获得,而中间的非同颜色的联通块的数量保持不变
则可以转化
$\Box $
对于以上两个引理,以及少量的组合数学知识,可得答案式子为:
\[Ans \\
= {cnt0-1 \choose seg0-1} \cdot {cnt1-1 \choose seg1-1} \pmod{998244353}
\]
其中 \(cnt0, cnt1\) 为 0/1 的数量, \(seg0, seg1\) 为 0/1 的联通块数量
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5, MOD = 998244353;
ll fac[N], inv[N];
ll C(ll x, ll y){
if(y == 0) return 1;
return fac[x] % MOD * inv[y] % MOD * inv[x-y] % MOD;
}
ll qp(ll x, ll y){
ll ret = 1;
while(y){
if(y&1) (ret *= x) %= MOD;
(x *= x) %= MOD;
y >>= 1;
}
return ret;
}
void init(){
fac[0] = 1;
inv[0] = 1;
for(int i = 1; i < N; i++){
fac[i] = fac[i-1] * i % MOD;
inv[i] = qp(fac[i], MOD-2);
// cout << inv[i] << endl;
}
}
void solve() {
int n; string s;
cin >> n >> s;
s = " " + s;
int cnt0 = 0, cnt1 = 0;
int seg0 = 0, seg1 = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == '0') cnt0++;
else cnt1++;
if (i == 0 || s[i] != s[i-1]) {
if (s[i] == '0') seg0++;
else seg1++;
}
}
ll ans = 1;
if (cnt0 > 0) ans = ans * C(cnt0 - 1, seg0 - 1) % MOD;
if (cnt1 > 0) ans = ans * C(cnt1 - 1, seg1 - 1) % MOD;
cout << ans << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll T = 1;
cin >> T;
// cout << "---------\n";
init();
// cout << "-------------\n";
while(T--){
solve();
}
return 0;
}
EOF
(洛谷怎么要求这么严格:

)
浙公网安备 33010602011771号