CF2255B 题解
albertting · · 题解
随便挑一个赛时会做的写个题解 /kel
朴素做法
似乎可以
正解
我们首先观察样例中的第一组。
初始时为:
我们初步观察到一个性质:
一个形如
这个简单手玩可以发现。证明(以向左翻为例)大概是可以选择左右各一个端点,使得
这个性质有什么用呢?
事实上,这个操作可以等价于任意重分配
于是我们发现实际上每个连续段块长
令
使用隔板法求分割为非负块长数,答案即为:
注意此时如果
这个式子和官解的式子是等价的。
Code
这是赛时代码,调试代码有点多,实际上是快速幂写挂了……
// Author: albertting
// Time: 2026/08/09 23:47:28
#include <bits/stdc++.h>
#define __Made return
#define in 0
#define China__ ;
#define ll long long
#define ld long double
#define lll __int128
#define pb push_back
#define uset unordered_set
#define umap unordered_map
using namespace std;
const ll P = 998244353;
ll qpow(ll a, ll b) {
if(b == 0) return 1;
ll res = qpow(a, b >> 1);
res = res * res % P;
if(b & 1) res = res * a % P;
return res;
}
ll fact[2000005], inv[2000005];
ll C(ll n, ll m) {
if(n <= 0 || m <= 0) return 1;
return fact[n] * inv[m] % P * inv[n - m] % P;
}
void solve() {
int n;
cin >> n;
string s;
cin >> s;
ll n0 = 0, n1 = 0, k0 = 0, k1 = 0;
int l = 0;
for(int r = 1; r < n; r++) {
if(s[r] == s[l]) continue;
if(s[l] == '0') n0 += r - l - 1, k0++;
else n1 += r - l - 1, k1++;
l = r;
}
if(s[l] == '0') n0 += n - l - 1, k0++;
else n1 += n - l - 1, k1++;
// clog << n0 << ' ' << k0 << ' ' << n1 << ' ' << k1 << '\n';
// clog << C(n0 + k0 - 1, k0 - 1) << ' ' << C(n1 + k1 - 1, k1 - 1) << '\n';
cout << C(n0 + k0 - 1, k0 - 1) * C(n1 + k1 - 1, k1 - 1) % P << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0), clog.tie(0);
fact[0] = inv[0] = 1;
for(ll i = 1; i <= 2000000; i++) {
fact[i] = fact[i - 1] * i % P;
inv[i] = qpow(fact[i], P - 2);
// if(i <= 10) clog << i << ": " << fact[i] << ' ' << inv[i] << '\n';
}
int t; cin >> t;
while(t--) solve();
__Made in China__
}