hdu4869 费马小+快速幂

思路:费马小+快速幂
      无论怎么翻,每一步的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
" ,sum);
   }
   return 0;
}
      
    

原文地址:https://www.cnblogs.com/csnd/p/12062931.html