hdu 4869 Turn the pokers(我取余又错了+1次)

题意:

给你N次操作,M张扑克,给你N个数A1,A2,..AN,其中Ai代表你i次操作能翻任意Ai张牌,求N次扑克牌操作后有多少种情况

 

想法:  我当时一直在做这题,当时没想到可以用区间去维护最后可能出现的1的个数。。  只是想到把前一个操作可能出现的1的个数往后一个操作递推。。。 但是酱紫时间复杂度N^2。。 

 

方法: 用一个区间[min,max] 去维护可能出现1的个数的情况, 设前一个操作翻A张牌,后一个操作翻B张牌,两次操作都翻了的牌的数目为C, 则两个操作之后可能出现的1的个数为A+B-2*C。。  可得出现1的个数要不全为奇数,要不全为偶数,所以用区间[min,max]中的所有奇数(偶数)去表示1出现的个数即可

 

求出1可能出现的个数之后,设min,min+2,min+4.... max为1可能出现的个数,则ans=(C(m, min)+ C(m, min+2) +..+ C(m,max) )%MOD;

计算(A/B)%MOD = (A*(B的逆元))%MOD时, 由费马小定理可得 当MOD为素数时,B的逆元为B^(MOD-2)%MOD

所以这题我们用二分快速幂可以算出结果

 

PS: 妈蛋啊 这题我取余又取错了。。。。  这已经不是第一次了。。坑爹啊。。

 

代码:

 

#include <cstdio>
#include <cstring>
#define LL long long
#define maxn 100005
#define MOD 1000000009

LL C[maxn];

int Fabs(int x)
{
	return x > 0? x: -x;
}

LL erfen(int a, int b)
{
	LL ans= 1;
	LL s= a;
	while(b)
	{
		if(b&1)
			ans= (ans * s)%MOD;
		s= (s * s)%MOD;
		b/= 2;	
	}
	return ans;
}

int main()
{
	int n, m;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		int min= 0;
		int max= 0;
		for(int i= 1; i<= n; i++)
		{
			int num;
			scanf("%d",&num);
			int _max= max;
			int _min= min;
			//max 更新 
			if(_max + num <= m) 
				max= _max+ num;
			else if(_min+ num<= m)
			{
				int xx= m- num;
				if(xx%2 == _max%2)  // 如果xx与_max奇偶性相同,代表xx可取 
					max= xx+ num;
				else    // 否则取x-1 
					max= xx+ num - 1;		
			}
			else if(_min+num > m)
				max= 2*m- (_min+ num);	
			//min的更新 
			if(num>= _max)
				min= num- _max;
			else if(num>= _min)
				min= num%2== _max%2? 0: 1;	
			else if(num< _min)	
				min= _min- num;
		}
		LL up= 1;
		LL down= 1;
		LL ans= 0;
		if(min== 0)
			ans++;
		for(int i= 1,j= m; i<= max; i++,j--)
		{
			up= (up * j)%MOD;
			down= (down * i)%MOD;
			if(i>= min && ( i- min )%2==0)
				ans= ( ans + (up * erfen(down,MOD-2) )%MOD ) %MOD;	 
		}
		printf("%lld\n",ans);
	}
	return 0;
}
 


 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值