思路
- 题目中的两个操作可以看成将一对整体的
11
与前(后)面的一个0
交换顺序。只有当一对11
与一个0
交换顺序时才会产生新的状态。 - 如果给出的数据中连续的
1
的个数是偶数,那么可以我们均分成x个11
。可以看出每一个11
,可以和任意的一个0
交换顺序。所以假设11
的个数位 a a a,0
的个数为 b b b, 则排列的方案有 ( a + b ) ! (a+b)! (a+b)! 种,11
内部排列不会产生新的状态,0
内部排列不会产生新的状态。所以去除重复的种类,答案就是 ( a + b ) ! a ! b ! \frac{(a+b)!}{a! b!} a!b!(a+b)!。 - 如果给出的数据中,不能均分为若干个
11
,如以下这种情况:01110
, 只能分成一对11
,我们这里假设分成最左边的1对11
。
01110
变成01011
, 其实也相当于最左边的一对11
,和最右端的一个0
交换顺序,所以答案和能均分的时候一样
AC代码
#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x; i<=y; ++i)
#define per(i,x,y) for(int i=x; i>=y; --i)
#define pushk push_back
#define popk pop_back
#define mem(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define ll long long
using namespace std;
const int N = 1e5+9;
const int mod = 998244353;
char s[N];
int f[N],inf[N];
int qmi(int x,int k){
int res=1;
while(k){
if(k&1) res=1ll*res*x%mod;
k>>=1;
x=1ll*x*x%mod;
}
return res;
}
void init(){
f[0]=1,inf[0]=1;
rep(i,1,N-1){
f[i]=1ll*f[i-1]*i%mod;
inf[i]=1ll*inf[i-1]*qmi(i,mod-2)%mod;
}
}
int main() {
init();
int T;
cin>>T;
while(T--){
int n;
scanf("%d",&n);
scanf("%s",s+1);
int cnt0=0,cnt1=0;
int x=0,y;
rep(i,1,n){
if(s[i]=='1') cnt1++;
else{
cnt0++;
x+=(cnt1/2);
cnt1=0;
}
}
x+=(cnt1/2);
y=cnt0;
//cout<<x<<" "<<y<<'\n';
int ans=1ll*f[x+y]*inf[x]%mod*inf[y]%mod;
printf("%d\n",ans);
}
return 0;
}
后记
是一道有趣的组合数学题目,思路参考了:https://www.cnblogs.com/Silymtics/p/solution-CF1545B.html