hdu 4869 组合数

来源:互联网 发布:达内linux视频 百度云 编辑:程序博客网 时间:2024/05/22 03:25

    设牌的正面为1,反面为0,则每翻一张牌就会使1的个数变更1,故不同的翻法之间1的个数相差0或2。得出结论:1、最后结果中的1的个数的奇偶性取决于所有翻牌数目之和的奇偶性。2、可能结果一定是连续间隔2的。

    故只要找出1可能个数的最小值mi和最大值ma,就可以知道1的所有可能值,然后求C(m,i)之和取模就好了。

    到第i次翻牌时,如果mi>=a[i],则mi=mi-a[i];否则如果ma>=a[i],a[i]和mi奇偶性相同时mi为0,不同时为1;否则mi=a[i]-ma;

    求最大值类似。

#include<iostream>#include<cstdio>#define ll long long#define p 1000000009#define N 100010using namespace std;ll fac[N];void init(){    int i;    fac[0] =1;    for(i =1; i <= 100000; i++)        fac[i] = fac[i-1]*i % p;}ll pow(ll a, ll b){    ll tmp = a % p, res =1;    while(b)    {        if(b &1)  res = res * tmp % p;        tmp = tmp*tmp % p;        b >>=1;    }    return  res;}ll C(ll n, ll m){    if(m > n)  return 0;    return  fac[n]*pow(fac[m]*fac[n-m], p-2) % p;}int main(){   //freopen("1.in","r",stdin);   ll n,m;   init();   while(scanf("%I64d%I64d",&n,&m)!=EOF)   {       ll mi=0,ma=0,x;       for(int i=0;i<n;i++)       {            scanf("%I64d",&x);            int u=mi;            if(x<=mi)mi-=x;            else if(x<=ma)mi=(mi%2)^(x%2);            else mi=x-ma;            if(x<=m-ma)ma+=x;            else if(x<=m-u)ma=m-((m%2)^((u+x)%2));            else ma=2*m-u-x;       }       ll ans=0;       for(ll i=mi;i<=ma;i+=2)ans=(ans+C(m,i))%p;       printf("%I64d\n",ans);   }   return 0;}


0 0
原创粉丝点击