题意:
就是现在如果给出一个串S是一个由01包含的串将这个串进行题意所说的变化, 每次取最后两个字符, 如果是"00"就变成“1”加到末尾, 如果是"01"或“10”或“11”, 就变成“0”来代替其加到末尾, 反复执行直到该串只剩下一个字符为止
现在给出n, m, g (0 <= n, m <= 10^5, n + m >= 1, g == 0 || g == 1)
求出如果一个串原本有n个0, m个1, 进行上诉变化之后得到的字符是g, 问原来的串的可能性有多少种, 最终结果多10^9 + 7取模输出
题解:
首先我们看到这个题肯定能得到这样的结论
(g=0的方案数)+(g=1的方案数)=C(n+m,m);
所以不论他让我们求(g=0的方案数)还是(g=1的方案数)我们都可以转换成求(g=0的方案数).为什么要转换成(g=0)呢?往下看。
分析题意:我们知道除了 00 00 00生成 1 1 1,其他的都生成 0 0 0。所以我们知道, 1 1 1不论跟什么放一起一定是 0 0 0那么,所以只要是1开头的串一定是0.那么我们就可以在确定偶数个0连续的基础上把1开头的串放在他们后面那一定是0,因为想到与奇数个0.
其实就是这种形式
00001...... 这是确定了4个0和1个1,所以(n+m-4-1)这个么多数组合就行了也就是C(n+m-4-1,m-1);
我们还需要特判一种情况 就是m=1就是只有一个1.
- 如果n是奇数,那么我们漏了一种把1放在最前面的情况,后面是奇数个0.
- 如果n是偶数,那么我们多加了一种,n个0+1
00001
这种情况,这种结果是1.
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+7;
const int mod=1e9+7;
ll n,m,cnt;
ll fac[maxn],infac[maxn];
ll qpow(ll a,ll b) {
ll sum=1;
while(b) {
if(b&1) sum=sum*a%mod;
b>>=1;
a=a*a%mod;
}
return sum;
}
void init() {
fac[0]=fac[1]=1;
for(int i=2; i<=200000; i++) {
fac[i]=fac[i-1]*i%mod;
}
for(int i=200000; i>=0; i--) {
infac[i]=qpow(fac[i],mod-2);
}
}
ll C(ll n,ll m) {
return fac[n]*infac[m]%mod*infac[n-m]%mod;
}
int main() {
ll g;
cin>>n>>m>>g;
if(n==0) {
///没有0 除了一个1之外不能构成1
if(g==0) {
if(m==1) printf("0\n");
else puts("1");
} else {
if(m==1) puts("1");
else puts("0");
}
return 0;
}
if(m==0) {
///没有1
if(g==1) {
///奇数个0可以构成1
if(n&1)printf("0\n");
else puts("1");
} else {
if(n&1)puts("1");
else puts("0");
}
return 0;
}
init();
ll all=C(n+m,m);
ll ans=0;///0的方案数
for(int i=0; i<=n; i+=2) {
ans=(ans+C(n-1-i+m,m-1))%mod;///除去确定的偶数个0和一个1
}
if(m==1&&(n&1)==0) {
ans=(ans-1+mod)%mod;
}
if(m==1&&(n&1)) {
ans=(ans+1)%mod;
}
if(g==0) printf("%lld\n",ans);
else printf("%lld\n",(all-ans+mod)%mod);
return 0;
}