LG 题解 CF1545B AquaMoon and Chess
Solution
你拿到这个题后开始手模它这个操作。
你发现,对于一个 11
移动的时候就相当于整体左移或者右移。
我们假设让它右移,如果它右边是一个 0
,那么它右移就相当于和这个 0
交换位置。如果它右边是一个 1
,实际并不能右移,但也可以看做它和这个 1
交换了一下位置。
那不难看出,和 0
交换位置时会产生新的状态,和 1
交换位置时并不会产生新的状态。
也不难看出,每一组 11
在整个序列中都是可以自由移动的。那么我们不妨将每个 11
都划分成一个整体,对于那些单独的 1
就直接扔掉。
那么对于剩下的 11
和 0
,显然可以随便安排他们的位置。
设有 \(x\) 个 11
和 \(y\) 个 0
,总排列数位 \((x+y)!\),因为有重复状态所以再除以 \(x! y!\),也就是说答案为 \(\binom{x+y}{x}\)。
直接预处理一个阶乘和逆元就可以 \(\mathcal O(1)\) 计算了。
至于 \(x\) 和 \(y\) 从原串中暴力找就可以。
Code
/*
Work by: Suzt_ilymtics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define int long long
#define orz cout<<"lkp AK IOI!"<<endl
using namespace std;
const int MAXN = 2e5+50;
const int INF = 1e9+7;
const int mod = 998244353;
int T, n;
int fac[MAXN], inv[MAXN];
char s[MAXN];
int read(){
int s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
return f ? -s : s;
}
void Init() {
int M = 200000;
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i = 2; i <= M; ++i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
for(int i = 2; i <= M; ++i) {
inv[i] = inv[i - 1] * inv[i] % mod;
}
}
int C(int n, int m) {
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
signed main()
{
Init();
T = read();
while(T--) {
n = read();
cin >> s + 1;
int y = 0, x = 0;
for(int i = 1; i <= n; ++i) if(s[i] == '0') y++;
for(int i = 2; i <= n; ++i) {
if(s[i] == '1' && s[i - 1] == '1') {
x++, s[i] = s[i - 1] = '0';
}
}
printf("%lld\n", C(x + y, x));
}
return 0;
}