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

题目大意:

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


你可能感兴趣的:(codeforces,组合数学,336D)