题目大意:
就是现在如果给出一个串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; }