思路:费马小+快速幂
无论怎么翻,每一步的1出现的可能个数的奇偶性是一样的,因为奇数 - 偶数 = 奇数,偶数 - 偶数 = 偶数,有一张牌被重叠了,那么就减去一个偶数2,所以怎么重叠都不会变(当前奇偶性与当前总翻牌数奇偶性一样),所以我们只要找到1的最大可能数,和最小可能数(当然最大和最小奇偶性一定相同),然后排列组合求和就行了,假如一共有10张牌,1出现的最大可能数是6 ,最小是2,那么ans = C(10 ,2) + C(10 ,4) + C(10 ,6).
最大和最小之间的同奇偶的数一定可以出现,就是搓1位,自己可以画画,这样又有一个蛋疼的问题,就是排列组合必然会涉及到除法,可是除法怎么处理这个 (a / b) % c因为他不等于 (a % c) / (b % c) ,乘法还可以,其实我们可以除法转化成乘法,使得(a / b) % c = a * pow(b ,c - 2) % c,这里的c是质数,下面证明一下
根据费马小定理有
a^(p - 1) % p = 1 % p
那么
(a^(p - 1) / a) % p = (1 / p) % p 则 a^(p - 2) = (1 / a) % p
除以a只要乘以1/a也就是乘以等号左侧,这样就把除法变成乘法。
注意成立的原因是在本题目里 a^(p-1)/p是一个大于等于p的数。
对于求1可能出现的次数min ,和max,就是分情况讨论,直接看代码自己模拟一下代码就懂了,这里就不解释了,全解释了读者看完也就没意思了。
#include<stdio.h>
#define MOD 1000000009
__int64 X[110000];
__int64 C[110000];
__int64 quick_pow(__int64 a ,__int64 b)
{
__int64 c = 1;
while(b)
{
if(b&1) c *= a;
a *= a ,b /= 2;
c %= MOD ,a %= MOD;
}
return c;
}
int main ()
{
int n ,m ,i;
while(~scanf("%d %d" ,&m ,&n))
{
for(i = 1 ;i <= m ;i ++)
scanf("%I64d" ,&X[i]);
__int64 MIN = 0 ,MAX = 0;
for(i = 1 ;i <= m ;i ++)
{
__int64 mi ,ma;
if(X[i] <= MIN) mi = MIN - X[i];
else if(X[i] > MAX) mi = X[i] - MAX;
else mi = (X[i]&1) != (MIN&1);
if(X[i] + MAX <= n) ma = X[i] + MAX;
else if(X[i] + MIN > n) ma = n * 2 - (MIN + X[i]);
else ma = ((X[i] + MIN) & 1) == (n & 1) ? n : n - 1;
MAX = ma ,MIN = mi;
}
__int64 sum = 0;
C[0] = 1;
if(MIN == 0) sum ++;
for(i = 1 ;i <= MAX ;i ++)
{
if(n - i < i) C[i] = C[n-i];
else
C[i] = C[i-1] * (n - i + 1) % MOD * quick_pow(i ,MOD - 2) % MOD;
if(i >= MIN && (i&1) == (MIN&1))
sum = (sum + C[i]) % MOD;
}
printf("%I64d\n" ,sum);
}
return 0;
}