hdu4869Turn the pokers 组合数学+求逆元

//m个卡片 , n次操作 , 每次操作可以将xi张卡片反转
//问最后有多少卡片的情况
//对于最后卡片的情况 , 1的数目个数的奇偶性肯定和奇数xi的个数的奇偶性一样
//因为奇数xi可以将1的个数加上奇数或者减去奇数 
//而且这个1的数目区间一定是连续的[st,en]
//那么就是维护st 和 en
//对于st是有1就翻1
//en是有0就翻0
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
typedef long long ll ;
const ll mod = 1000000009 ;
const int maxn =1e5+10 ;
ll c[maxn] ;
ll  exgcd(ll a , ll b , ll &x , ll &y)
{
    if(b == 0)
    {
        x = 1 ;
        y = 0 ;
        return a ;
    }
    ll r = exgcd(b , a%b , x , y) ;
    ll tmp = x  ;
    x = y;
    y = tmp - a/b*y ;
    return r ;
}
int main()
{
  //  freopen("in.txt" ,"r" , stdin) ;
    int  n , m ;
    while(~scanf("%d%d" , &n , &m))
    {
        ll st = 0  , en = 0 ;
        ll sum = 0 ;
        for(int i = 1;i <= n;i++)
        {
            int t ;
            scanf("%d" , &t) ;
            sum += t ;
            int mi = st ;
            int ma = en ;

            if(st >= t)
            mi = st - t ;
            else if(en >= t)
            mi = 0 ;
            else mi = t - en ;

            if(m - en >= t)
            ma = en + t ;
            else if(m - st >= t)
            ma = m ;
            else
            ma = 2*m - st - t ;

            st = mi ;
            en = ma ;
        }
        ll ans = 0  ;
        c[0] = 1 ;
        for(int i = 1;i <= m;i++)
        {
            ll x , y ;
            exgcd((ll)i  ,mod , x , y) ;
            c[i] = x*(ll)(m-i+1)%mod*c[i-1]%mod ;
        }
        st = (st&1) == (sum&1) ? st : (st+1) ;
        for(int i = st;i <= en;i+= 2)
        ans = (ans + c[i])%mod ;
        cout<<(ans+mod)%mod<<endl;
    }
    return  0 ;
}



你可能感兴趣的:(hdu4869Turn the pokers 组合数学+求逆元)