[Codeforces 336D] Vasily the Bear and Beautiful Strings //组合数学

题目链接

题意:定义modification操作为取string(长度>=2)的最后两个字符,如果为(01,10,11)则将这两个字符变为0;如果为00,则将其变为1。
给定n,m,g [0<=n,m<=1e5,0<=g<=1]
问有多少个不同的string,符合以下条件:
①string中有n个0,m个1
②string经过任意次modification操作后,string变为字符g

思路:首先要知道 n个0 和 m个1 的排列为 ( n + m ) ! n ! m ! \frac{(n+m)!}{n!*m!}
然后,从一个字符开始:设当前剩余k0个0,k1个1
(1) 如果g是0,可以把它变成11、10、01
····· 对于11和10,不看第一个1,第二个数是0或1都可以,所以直接求 k0个0 和 (k1-1)个1 的排列累加到ans即可。(程序里是先判断了k1是否不为0)
····· 对于01,就是用掉一个0,然后把g变成1,继续走
(2) 如果g是1,只能把它变成00,即用掉一个0,然后把g变成0,继续走
因为两个操作都是用掉一个0,所以循环n次就用完了所有的0。
最终,0全用完,剩余一个下一位的g 和 k1个1,但是有如下情况也是合法却没被排列公式计算到的:
… ①如果g是1,因为1只能变成00,但是已经没有剩余的0了,所以此时允许k1是0或1,(0是因为直接舍弃这个g,1是因为让这一位就是1)
… ②如果g是0,因为0可以变成11、10、01,这里,如果k1为2,我们可以直接把g变成11;如果k1为3,我们可以先把g变成10,然后把后面的0变成11,即111;如果k1为4,同理,先变出来110,再把后面的0变成11,就有了1111,etc. 即此时k1可以为>=2的任意值
所以如果是上述(1)(2)两个情况的话,结果应该+1。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll p=1e9+7;
const int N=2e5+7;
ll n,m,jc[N],ans;
int g;
void init(){//预处理阶乘
	jc[0]=1;
	for(ll i=1;i<=2e5;i++)jc[i]=jc[i-1]*i%p;
}
ll qpow(ll x,ll e,ll mod){
	ll re=1;
	while(e){
		if(e&1){
			re=re*x%mod;
		}
		x=x*x%mod;
		e>>=1; 
	} 
	return re%mod;
}
ll A(ll a,ll b){//a个0 和 b个1的排列
	ll up=jc[a+b],down=jc[a]*jc[b]%p;
	ll re=up*qpow(down,p-2,p)%p;
	return re;
}
int main(){
	init();
	cin>>n>>m>>g;
	ll k0=n,k1=m;
	for(ll i=1;i<=n;i++){
		if(g==0){
			g=1;
			if(k1)ans=(ans+A(k0,k1-1))%p;
			k0--;
		}else{
			g=0;
			k0--;
		}
	}
	if((g==1&&k1<2)||(g==0&&k1>=2))ans=(ans+1)%p;
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/105231756