hdu_4869(费马小定理+快速幂)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4869

Turn the pokers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2001    Accepted Submission(s): 707


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
3 4 3 2 3 3 3 3 2 3
 


Sample Output
8 3
Hint
For the second example: 0 express face down,1 express face up Initial state 000 The first result:000->111->001->110 The second result:000->111->100->011 The third result:000->111->010->101 So, there are three kinds of results(110,011,101)
 


Author
FZU
 


Source
完全学习的http://blog.csdn.net/libin56842/article/details/38065951,感谢
通过这个学习了快速幂和费马小定理的应用
一、快速幂:
  对于a^n可以用分治的思想令a^n = a^(n/2)*a^(n/2) 注意要分奇偶。
  一种直观的用递归表示的方法如下:
    
1 LL quickmod(LL a,LL b)
2 {
3     LL ans = 1;
4     if(b==0) return ans;
5     if(b&1) ans = (ans*a)%mod;
6     return ans = (quickmod(a,b/2))%mod;
7 })%mod;

  为了降低复杂度。我们现在展开这个递归式子,写一个非递归的程序:

  

1.如果b是偶数,我们可以记k = a2 mod c,那么求(k)b/2 mod c就可以了。

2.如果b是奇数,我们也可以记k = a2 mod c,那么求

((k)b/2 mod c × a ) mod c =((k)b/2 mod c * a) mod c 就可以了。

上述过程最后一定是b先等于1再等于0,故b=0时候结束程序

  下面是模板代码:

 1 LL quickmod(LL a,LL b)
 2 {
 3     LL ans = 1;
 4     while(b)
 5     {
 6         if(b&1) ans = (ans*a)%mod;
 7         a = (a*a)%mod;
 8         b>>=1;
 9     }
10     return ans;
11 }

下面介绍一下费马小定理:

  a^(p-1) = 1(mod p)  p是素数

  一般应用有: 

A: a^b mod p 在b很大的时候可以先用b = b % (p-1)

B:   在阶乘中减去除法的操作。a^(p-2) = 1/a(mod p)

这个题就应用了B

下面是这个题的ac代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define LL long long
 7 const LL mod = 1000000009;
 8 const int N = 100005;
 9 
10 LL f[N];
11 
12 void init()
13 {
14     int i;
15     f[0] = 1;
16     for(i = 1; i < N; i++)
17         f[i] = (f[i-1]*i)%mod;
18 }
19 
20 LL quickmod(LL a, LL b)
21 {
22     LL ans = 1;
23     while(b)
24     {
25         if(b&1){
26             ans = (ans*a)%mod;
27         }
28         b>>=1;
29         a = (a*a)%mod;
30     }
31     return ans;
32 }
33 
34 int main()
35 {
36     int n,m,i,j,k,l,r,x,ll,rr;//ll保存最小的1的个数
37     //l表示上一次的最小的1的个数,rr保存的是最多的1的个数
38     //r表示的是上一次的最多的1的个数
39     init();
40     while(~scanf("%d%d",&n,&m))
41     {
42         l = r = 0;
43         for( i = 0; i < n; i++)
44         {
45             scanf("%d",&x);
46             if(l>=x) ll = l - x;
47             else if(r>=x) ll = ((l%2)==(x%2))?0:1;
48             else ll = x-r;
49 
50             if(r+x<=m) rr = r+x;
51             else if(l+x<=m) rr = (((l+x)%2)==(m%2)?m:m-1);
52             else rr = 2*m-(l+x);
53 
54             l = ll;
55             r = rr;
56         }
57         LL sum = 0;
58         for(i = l; i<=r; i+=2)
59             sum+=((f[m]%mod)*(quickmod((f[i]*f[m-i])%mod,mod-2)%mod))%mod;
60         printf("%I64d\n",sum%mod);
61     }
62     return 0;
63 }
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 using namespace std;
 6 #define mod 1000000009
 7 #define LL __int64
 8 #define maxn 100000+5
 9 
10 LL f[maxn];
11 
12 void set()
13 {
14     int i;
15     f[0] = 1;
16     for(i = 1; i<maxn; i++)
17         f[i] = (f[i-1]*i)%mod;
18 }
19 
20 LL quickmod(LL a,LL b)
21 {
22     LL ans = 1;
23     while(b)
24     {
25         if(b&1)
26         {
27             ans = (ans*a)%mod;
28             b--;
29         }
30         b/=2;
31         a = ((a%mod)*(a%mod))%mod;
32     }
33     return ans;
34 }
35 
36 int main()
37 {
38     int n,m,i,j,k,l,r,x,ll,rr;
39     set();
40     while(~scanf("%d%d",&n,&m))
41     {
42         l = r = 0;
43         for(i = 0; i<n; i++)
44         {
45             scanf("%d",&x);
46             //计算最小的1的个数,尽可能多的让1->0
47             if(l>=x) ll = l-x;//当最小的1个数大于x,把x个1全部翻转
48             else if(r>=x) ll = ((l%2)==(x%2))?0:1;//当l<x<=r,由于无论怎么翻,其奇偶性必定相等,所以看l的奇偶性与x是否相同,相同那么知道最小必定变为0,否则变为1
49             else ll = x-r;//当x>r,那么在把1全部变为0的同时,还有x-r个0变为1
50             //计算最大的1的个数,尽可能多的让0->1
51             if(r+x<=m) rr = r+x;//当r+x<=m的情况下,全部变为1
52             else if(l+x<=m) rr = (((l+x)%2) == (m%2)?m:m-1);//在r+x>m但是l+x<=m的情况下,也是判断奇偶,同态那么必定在中间有一种能全部变为1,否则至少有一张必定为0
53             else rr = 2*m-(l+x);//在l+x>m的情况下,等于我首先把m个1变为了0,那么我还要翻(l+x-m)张,所以最终得到m-(l+x-m)个1
54 
55             l = ll,r = rr;
56         }
57         LL sum = 0;
58         for(i = l; i<=r; i+=2)//使用费马小定理和快速幂的方法求和
59             sum+=((f[m]%mod)*(quickmod((f[i]*f[m-i])%mod,mod-2)%mod))%mod;
60         printf("%I64d\n",sum%mod);
61     }
62 
63     return 0;
64 }

 

posted on 2016-04-12 20:54  若流芳千古  阅读(499)  评论(0编辑  收藏  举报

导航