HDU1869Turn the pokers

Turn the pokers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2164    Accepted Submission(s): 772


Problem Description
During summer vacation,Alice stay at home for a long time, with nothing to do. She went out and bought m pokers, tending to play poker. But she hated the traditional gameplay. She wants to change. She puts these pokers face down, she decided to flip poker n times, and each time she can flip Xi pokers. She wanted to know how many the results does she get. Can you help her solve this problem?
 

Input
The input consists of multiple test cases.
Each test case begins with a line containing two non-negative integers n and m(0<n,m<=100000).
The next line contains n integers Xi(0<=Xi<=m).
 

Output
Output the required answer modulo 1000000009 for each test case, one per line.
 

Sample Input
  
  
3 4 3 2 3 3 3 3 2 3
 

Sample Output
  
  
8 3
Hint
For the second example: 0 express face down,1 express face up Initial state 000 The first result:000->111->001->110 The second result:000->111->100->011 The third result:000->111->010->101 So, there are three kinds of results(110,011,101)
 题目给出操作数,让我们翻转该数量的牌,求最后的不同的牌数量。假设正面1,反面0,翻n次牌,我们求出翻牌为1的下限和上限,然后组合数该区间求得sum
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

#define mod 1000000009
#define LL __int64
#define maxn 100000+5

LL f[maxn];

void set()
{
    int i;
    f[0] = 1;
    for(i = 1; i<maxn; i++)
        f[i] = (f[i-1]*i)%mod;
}
LL get_power(LL n,LL p)//快速幂
{
    LL now=1;
    while(p)
    {
        if(p&1)
        {
            now=(now*n)%mod;
            p--;
        }
        p/=2;
        n=(n*n)%mod;
    }
    return now;
}
int main()
{
    int n,m,i,maxm,minm,rr,ll,x;
    set();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        minm=maxm=0;//l代表最小1,r代表最大1,我们利用他们之间的区间幂求sum
        while(n--)
        {
            scanf("%d",&x);
            if(minm>=x)//1
            ll=minm-x;
            else if(maxm>=x)//2
            ll=((minm%2)==(x%2)?0:1);
            else//3
            ll=x-maxm;
            if(maxm+x<=m)//4
            rr=maxm+x;
            else if(minm+x<=m)//5
            rr=(((minm+x)%2)==(m%2)?m:m-1);
            else//6
            rr=2*m-(minm+x);
            minm=ll,maxm=rr;
/*①:当前下限大于等于现在翻牌的数量,这个比较好理解,全翻1,1变成0,则剩下的1就是minm-x

②:当前下限小于翻牌数量,上限大于等于翻牌数量,因为翻牌数量刚好在上下限之间,
所以最少可以把正面朝上的数量减为零,但不是绝对能减到0,因为有可能当前正面朝上的牌时奇数,
而翻牌数量是偶数,所以要判断奇偶性是否一样,为什么要和minm比较奇偶性,后面会说。

③:翻牌数量比上限还大的时候,直接减去上限就是下限,也不难理解

④:上限+翻牌数量没有达到总牌数时,上限+翻牌数量就是新的上限,全翻0,这样使1最多

⑤:上限+翻牌数量大于总牌数,而下限+翻牌数量小于等于总牌数,
前者可以说是翻牌溢出了,已经全是1再翻的话只会让一些1变成0,后者没有达到全变成1的情况。
它们是一个上限一个下限,这说明可以处理到在这之间的情况,
那么最好的结果是所有牌都正面朝上,全是1,和②的情况一样,需要判断奇偶性是否一致,
这回和m比较,应该比②的好理解

⑥:上限+翻牌数、下限+翻牌数全都大于总牌数时,说明都会溢出,
那就用2 * m - (x + minm)来表示上限,因为(x+minm)小,所以溢出的1变成0的牌数少。
我之前用max(maxm + x - m, 2 * m - (x + minm))来表示⑥的上限,结果WA了,
其实是我想错了,maxm + x - m是1变成0的牌的数量,而要找的是1的上限。*/
        }
        LL sum=0;
        for(i=minm;i<=maxm;i+=2)
        sum+=((f[m]%mod)*(get_power((f[i]*f[m-i])%mod,mod-2)%mod))%mod;
        printf("%I64d\n",sum%mod);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值