CF2255B A Ribbon for Tomorrow

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;
}
posted @ 2026-08-26 23:03  superl61  阅读(4)  评论(0)    收藏  举报