CF1545B AquaMoon and Chess(要不再看一下?)
题目大意:
你有一个长为 \(n\) 的棋盘,这个棋盘上有一些棋子,你可以进行如下操作:
如果第 \(i + 2\) 个位置是空的,且第 \(i + 1\) 个位置非空,则可以将第 ii 个位置的棋子挪到第 \(i+2\) 个位置 (\(i + 2 \leq n\)).
如果第 i - 2i−2 个位置是空的,且第 \(i - 1\) 个位置非空,则可以将第 \(i\) 个位置的棋子挪到第 \(i - 2\) 个位置 (\(i−2≥1\)).
现在将给出一个棋盘的初始状态,求可以通过上述操作可以到达的状态数,你可以进行任意次操作,答案对 \(998244353998244353\) 取模。
分析:
初看题目,似乎并不像一个组合数学的题。似乎只能暴力
参考了一些想法之后,发现在整个棋盘中,如果相邻两个位置全都有棋子,那么这两个棋子就可以自由移动,如果一个棋子左右都是空位,那么它就只能被迫移动(即相邻两个棋子移动到它旁边时它可以借助其中一个棋子进行移动),但这样的移动势必会导致另一个棋子变成这样的一个不能移动的棋子,因此我们可以断言:一个棋盘中单独的棋子数量和能够自由移动的棋对的数量是恒定的,由初始状态决定。
设单独的棋子的数量为 \(tot1\),能自由移动的棋对的数量为 \(tot2\),则答案为:
\[tot2 + tot1 \choose tot2
\]
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD = 998244353;
const int MAXN = 1e5;
int n,inv[MAXN + 5],f[MAXN + 5];
bool vis[MAXN + 5];
string a;
int qpow(int a,int n){
int ret = 1;
while(n){
if(n % 2 == 1){
ret *= a % MOD;
ret %= MOD;
}
n /= 2;
a =a * a % MOD;
}
return ret;
}
int c(int n,int m){
return (f[n] * inv[m]) % MOD * inv[n - m] % MOD;
}
signed main(){
f[0] = 1;
for(int i = 1; i <= MAXN; i++){
f[i] = f[i - 1] * i;
f[i] %= MOD;
//cout << f[i] << "\n";
}
inv[MAXN] = qpow(f[MAXN],MOD - 2);
for(int i = MAXN; i >= 1; i --){
inv[i - 1] = inv[i] * i % MOD;
}
int t;
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
memset(vis,0,sizeof vis);
int cnt1 = 0,cnt2 = 0;
cin >> a;
for(int i = 0; i < n; i++){
if(a[i] == '0')cnt2++;
if(a[i] == '1' && a[i + 1] == '1' && !vis[i] && !vis[i + 1]){
vis[i] = vis[i + 1] = 1;
cnt1++;
}
}
cout << c(cnt1 + cnt2,cnt1) << "\n";
}
}