【组合数学】 HDOJ Turn the pokers

经过n次翻牌以后,我们能得到在m张牌中最少有多少张1,和最多有几张1。然后翻牌数之和的奇偶性和1的张数的奇偶性一致。然后我们就对1的张数最少到最多求和。。就是答案了。。。中间要用到逆元。。因为算组合数不能打表(空间不够)。。也不能一层一层推(时间不够)。。。只能用扩展欧几里得来求了。。。

#include <iostream>  
#include <queue>  
#include <stack>  
#include <map>  
#include <set>  
#include <bitset>  
#include <cstdio>  
#include <algorithm>  
#include <cstring>  
#include <climits>  
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 100005
#define eps 1e-10
#define mod 1000000009
#define INF 99999999  
#define lowbit(x) (x&(-x))  
//#define lson o<<1, L, mid  
//#define rson o<<1 | 1, mid+1, R  
typedef long long LL;
//typedef int LL;
using namespace std;

LL n, m;
void extend_gcd(LL a, LL b, LL &d, LL &x, LL &y)
{
	if(b == 0) { d = a, x = 1, y = 0; }
	else { extend_gcd(b, a%b, d, y, x), y -= x*(a/b); }
}
LL c[maxn];
int main(void)
{
	LL a, b, aa, bb, i, x;
	LL g, y, ans;
	while(scanf("%I64d%I64d", &n, &m)!=EOF) {
		a = b = 0;
		for(i = 0; i < n; i++) {
			scanf("%I64d", &x);
			if(a >= x) aa = a-x;
			else if(b <= x) aa = x-b;
			else {
				if((a%2 && x%2) || (a%2 == 0 && x%2 == 0)) aa = 0;
				else aa = 1;
			}
			
			if(b+x <= m) bb = b+x;
			else if(a+x >= m) bb = m+m-a-x;
			else {
				if((((a+x)%2) && m%2) || (((a+x)%2 == 0) && m%2 == 0)) bb = m;
				else bb = m-1;
			}
			a = aa, b = bb;
		}
		c[0] = 1, ans = 0;
		for(i = 1; i <= m; i++) {
			extend_gcd(i, mod, g, x, y);
			x=(x%mod+mod)%mod;
			c[i] = c[i-1]*(m-i+1)%mod*x%mod;
		}
		for(i = a; i <= b; i+=2) {
			ans += c[i];
			ans %=mod;
		}
		printf("%I64d\n", ans);
	}
	return 0;
}


你可能感兴趣的:(HDU)