[hdu 4869](14年多校I题)Turn the pokers 找规律+拓欧逆元

Turn the pokers


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




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)


题目大意

给定M张牌,能够翻转N次。每次能够翻转恰好Xi张牌。刚開始牌面所有朝下,问经过N次翻转之后可能产生的扑克序列数(如例子hint)。

解题思路

现场还是没出……想到dp的思路但复杂度高达N^2.

能够观察到,我们最后正面朝上的牌的数量奇偶总是一定的(如1,3。5),由于不同奇偶情况就须要至少多翻一次,但翻动的次数已经固定不能更改。


考虑一次翻转,最多X1张牌正面朝上了。最少也是X1张。

假设第二次仅仅翻转1张,再设1<X1<m 则最多会有X1+1张牌正面朝上,最少会有X1-1张牌正面朝上。


如今如果我们已经翻好k-1次

最多a张正面朝上,最少b张正面朝上

假设b>=Xk 则翻转后最少有b-Xk张正面朝上(其余的情况能够一次翻一张正面的,一张反面的。情况保持不变)。

否则。假设a>Xk。这时最少会有0张或1张正面朝上(依据a和Xk的奇偶性推断),

再否则,最少会有Ak-a张正面朝上(先把正面朝上的所有翻转,剩下的再翻便是最少张数)


关于最大值的讨论同理


最后关于组合数的计算,因为m固定不变,就能够依据组合数公式C(m,n)=C(m-1,n)*(n-m+1)/m 线性求解。因为1e9+9是大素数。除法操作可用逆元求解取代。

#include <cstdio>
#define LL long long
int n,m;
LL mod=1000000009;
LL a[100005];
void egcd(LL a,LL b,LL &x,LL &y)
{
  if (b==0)
  {
    x=1;y=0;
    return ;
  }
  egcd(b,a%b,x,y);
  LL t=x;
  x=y,y=t-a/b*y;
  return;
}
LL cal(LL x,LL y)
{
  LL cur=1,tmp=0,t=0;
  while(t<=y)
  {
    if (t>=x&&t<=y)
    if ((t-x)%2==0) tmp=(tmp+cur)%mod;
    t++;
    cur=cur*(m-t+1)%mod;
    LL t1,t2;
    egcd(t,mod,t1,t2);
    t1=(t1+mod)%mod;
    cur=cur*t1%mod;
  }
  return tmp;
}
int main()
{
  while (~scanf("%d%d",&n,&m)){
  LL upper,lower,plower,pupper;
  for (int i=1;i<=n;i++)
    scanf("%I64d",&a[i]);
  upper=lower=pupper=plower=0;
  for (int i=1;i<=n;i++)
  {
    if (plower>=a[i]) lower-=a[i];
    else if (pupper>=a[i]) lower=0+((pupper+a[i])%2==1);
    else lower=a[i]-pupper;
    if (pupper+a[i]<=m) upper+=a[i];
    else if (plower+a[i]<=m) upper=m-((plower+a[i])%2==1);
    else {upper=m-(plower+a[i]-m);}
    plower=lower;//plower代表上一步的最小值
    pupper=upper;//pupper代表上一步的最大值
  }
    printf("%I64d\n",cal(lower,upper));
  }
  return 0;
}




转载于:https://www.cnblogs.com/zsychanpin/p/6869085.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值