Codeforces Round #732 (Div. 2) D. AquaMoon and Chess(排列组合/组合数)
Cirno gave AquaMoon a chessboard of size 1×𝑛1×n. Its cells are numbered with integers from 11 to 𝑛n from left to right. In the beginning, some of the cells are occupied with at most one pawn, and other cells are unoccupied.
In each operation, AquaMoon can choose a cell 𝑖i with a pawn, and do either of the following (if possible):
- Move pawn from it to the (𝑖+2)(i+2)-th cell, if 𝑖+2≤𝑛i+2≤n and the (𝑖+1)(i+1)-th cell is occupied and the (𝑖+2)(i+2)-th cell is unoccupied.
- Move pawn from it to the (𝑖−2)(i−2)-th cell, if 𝑖−2≥1i−2≥1 and the (𝑖−1)(i−1)-th cell is occupied and the (𝑖−2)(i−2)-th cell is unoccupied.
You are given an initial state of the chessboard. AquaMoon wants to count the number of states reachable from the initial state with some sequence of operations. But she is not good at programming. Can you help her? As the answer can be large find it modulo 998244353998244353.
Input
The input consists of multiple test cases. The first line contains a single integer 𝑡t (1≤𝑡≤100001≤t≤10000) — the number of test cases.
The first line contains a single integer 𝑛n (1≤𝑛≤1051≤n≤105) — the size of the chessboard.
The second line contains a string of 𝑛n characters, consists of characters "0" and "1". If the 𝑖i-th character is "1", the 𝑖i-th cell is initially occupied; otherwise, the 𝑖i-th cell is initially unoccupied.
It is guaranteed that the sum of 𝑛n over all test cases does not exceed 105105.
Output
For each test case, print the number of states that reachable from the initial state with some sequence of operations modulo 998244353998244353.
Example
input
Copy
6
4
0110
6
011011
5
01010
20
10001111110110111000
20
00110110100110111101
20
11101111011000100010
output
Copy
3
6
1
1287
1287
715
注意到题目给的移动的限制,实际上就是相邻的两个1可以接力一样地来回移动且不能分开。同时如果有连续的一串1,有奇数个1的话有一个1实际上永远不会动(把这个1去掉即可,因为最终得到的所有的状态的这个位置都是1,当然随便去掉哪个都ok),其他相邻的1两两一组可以来回跑,如果有偶数个1相邻的1两两一组可以来回跑。所以最终就转换成了一个排列组合问题:设n为组数(两个相邻的1为一组),m为0的个数,求n球入m不同盒的方案数,答案就是\(C_{m + n}^{m}\)。
#include <bits/stdc++.h>
using namespace std;
int n;
#define LL long long
#define p 998244353
const int maxn=1000005;
void extend_gcd(LL a,LL b,LL &x,LL &y){
if(b==0){
x=1,y=0;
return;
}
extend_gcd(b,a%b,y,x);
y-=a/b*x;
}
LL inv[maxn+10];
LL f[maxn+10];
void init(){//阶乘及其逆元打表
f[0]=1;
for(int i=1;i<=maxn;i++){
f[i]=f[i-1]*i%p;
}
LL x,y;
extend_gcd(f[maxn],p,x,y);//先求出f[N]的逆元,再循环求出f[1~N-1]的逆元
inv[maxn]=(x%p+p)%p;
for(int i=maxn-1;i>=1;i--){
inv[i]=inv[i+1]*(i+1)%p;
}
}
LL C(LL n,LL m){
if(n==m||m==0)return 1;
return (f[n]*inv[m]%p*inv[n-m]%p)%p;
}
int main() {
int t;
cin >> t;
init();
while(t--) {
string s;
int nn;
cin >> nn;
cin >> s;
int n = 0, m = 0;
int lst = -1;
for(int i = 0; i < s.size(); i++) {
if(i == 0) {
if(s[0] == '0') m++;
else {
lst = 0;
}
continue;
}
if(s[i] == '0') {
m++;
if(s[i - 1] == '1') {
int len = i - lst;
n += len / 2;
}
} else {
if(s[i - 1] == '0') {
lst = i;
}
}
}
if(s[s.size() - 1] == '1') {
int len = s.size() - lst;
n += len / 2;
}
cout << C(n + m, m) << endl;
}
return 0;
}