题目大意:
就是现在如果给出一个串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取模输出
大致思路:
由于字符串变化后结果一定是0或者1, 我们只需要考虑g == 0的情况即可(g == 1的直接用所有排列来减去即可)
首先观察到如果1出现在字符中, 那么1后面无论是什么值"10"和“11”的结果都是0, 所以说可以将1视为置0符
那么如果一个串是偶数个0加上一个1的开头, 且1的后面有字符, 得到的结果相当于偶数的0的字符串进行变化, 结果一定是0
所以枚举前面有2*k个0, 然后紧跟一个1, 剩下的n - 2*k个0和m - 1个1任意排列有C(n - 2*k + m - 1, m - 1)种
这个枚举有一些要注意的是当只有1个1的时候这个1不能放在所有0的前面, 例如“001”结果是1
还有就是奇数个0, 且只有一个1的时候1可以放在最后面例如“10”或者“1000”结果是0, 这个情况额外考虑
另外判断一下上面两种特殊情况即可
代码如下:
Result : Accepted Memory : 1668 KB Time : 124 ms
/*
* Author: Gatevin
* Created Time: 2015/2/27 18:17:29
* File Name: poi~.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
const lint mod = 1000000007LL;
int n, m, g;
lint fac[200010];
void init()
{
fac[0] = fac[1] = 1;
for(int i = 2; i <= 200000; i++)
fac[i] = fac[i - 1] * i % mod;
return;
}
lint quick_pow(lint base, lint pow)
{
lint ret = 1;
while(pow)
{
if(pow & 1)
ret = (ret * base) % mod;
base = base * base % mod;
pow >>= 1;
}
return ret;
}
lint C(int r, int k)//C[r][k]
{
return fac[r]*quick_pow(fac[k]*fac[r - k] % mod, mod - 2LL) % mod;
}
int main()
{
scanf("%d %d %d", &n, &m, &g);
if(n == 0)
{
if(g == 0)
{
if(m == 1)
printf("0\n");
else
printf("1\n");
}
else
{
if(m == 1)
printf("1\n");
else
printf("0\n");
}
return 0;
}
if(m == 0)
{
if(g == 0)
{
if(n & 1)
printf("1\n");
else
printf("0\n");
}
else
{
if(n & 1)
printf("0\n");
else
printf("1\n");
}
return 0;
}
init();
lint all = C(n + m, n);
lint ans = 0;
for(int t = 0; t <= n; t += 2)//末尾的0的个数, 然后放一个1
ans = (ans + C(n + m - 1 - t, m - 1)) % mod;
if(m == 1 && (n & 1) == 0)//只有一个1, 偶数个0的时候1不能放在所有0的后面, 之前一种排列不能算
ans = (ans - 1 + mod) % mod;
if(m == 1 && (n & 1))//只有一个1, 奇数个0的时候1还可以放在最前面(末尾奇数个0), 要多加上一种选择
ans = (ans + 1) % mod;
if(g == 0)
printf("%I64d\n", ans);
else
printf("%I64d\n", (all - ans + mod) % mod);
return 0;
}