Turn the pokersTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1898 Accepted Submission(s): 671
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
Sample Output
|
表示看了一天了。。。 (⊙o⊙)
题意:有m张牌,1代表牌是面朝上的,0代表牌是面朝下的,初始默认牌都是朝下的。
现在有n次操作,每次操作都会翻转数目为x(1 <= x <= m)的牌这也意味着要改变它的状态。
问你n次操作后,m张牌的最后状态有多少种?
逆元:由费马小定理a ^ (p-1) = 1 (%p),两边同时除去a——a ^ (p-2) = a^-1 (%p),得a的逆元a^-1 = a ^ (p-2)。
大牛题解:点我
奇偶性真是好东西。。。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100000+10
#define MOD 1000000009
#define LL long long
using namespace std;
LL pow_mod(LL a, LL n)//费马小定理 求解逆元
{
LL ans = 1;
while(n)
{
if(n & 1)
ans = ans * a % MOD;
a = a * a % MOD;
n >>= 1;
}
return ans;
}
LL c[MAXN];
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF)
{
int Min = 0, Max = 0;//最少1的个数 最多1的个数
int t1, t2, x;
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
//求解最少的1的个数 每次最小化1的个数
if(Min >= x)
t1 = Min - x;
else if(Max >= x)// Min <= x <= Max
t1 = ((Min&1) == (x&1)?0:1);//奇偶性相同 可以达到最优的状态
//t1 = min(m-x+Min, Max-x);
else
t1 = x - Max;
//求解最多的1的个数 每次最大化1的个数
if(m - Max >= x)
t2 = Max + x;
else if(m - Min >= x)
t2 = (((Min+x)&1) == (m&1) ? m :m-1);//同上
//t2 = max(2*m - x - Max, Min+x);
else
t2 = 2*m - x - Min;
Min = t1, Max = t2;
}
//求解组合数
LL ans = 0;
c[0] = 1;
if(Min == 0)//最少的1的个数为0
ans = 1;
for(int i = 1; i <= Max; i++)
{
if(2*i > m)
c[i] = c[m-i];//组合数规律 m里面取i个 和取m-i个一样
else
c[i] = c[i-1] * (m-i+1) % MOD * pow_mod(i, MOD-2) % MOD;//利用逆元 求解
if(Min <= i && (Min&1) == (i&1))
ans += c[i], ans %= MOD;
}
printf("%lld\n", ans);
}
return 0;
}