hdu 4704 sum 费马小定理 快速幂
---恢复内容开始---
Problem Description
Sample Input
2
Sample Output
2
Hint
1. For N = 2, S(1) = S(2) = 1. 2. The input file consists of multiple test cases.
Source
题意:给出一个整数N, s(k)代表N的一个个数不超过k的拆分
比如N=4, s(1)就是3, s(2)可以是(2, 2), (1, 3), (3, 1)……
求s(k)(k=1~N)的总和,就是求整数N的有序拆分的总数,分析易得为2^(n-1);
一开始不知道费马小定理,于是卡题了,只知道是大数……
费马小定理为对于一个素数p,对于任何自然数n,都满足a^(p-1)≡1(mod p);
利用费马小定理可以化简a^b%m取模
比如,设p=7, n=32, 求2^32≡x(mod p)的值
由于p是素数,所以一定存在2^6≡1(mod p)
则
2^32%p
=(2^[(6*5)+2])%p
=[2^(6*5)*2^2]%p
=[(2^(6*5)%p)*(2^2%p)]%p //(a*b)%m=[(a%m)*(b%m)]%m;
=[1*(2^2%p)]%p //2^(6*5)%p为对费马小定理的应用
=2^2%p;
对于任意自然数,当要求a^p%m时,就可以利用费马小定理化简,只需求(a^(m%p))%p;(p是素数)
所以,先以字符串形式读入整数N,然后对模MOD,得到余数d,再利用快速寞计算
*如何处理n-1次方
注意此处要求的是2的n-1次方.一般来说,那么若原数据再减一,取模值应该为d-1
但有特殊情况,比如原数刚好是MOD倍数,取模后值为0,则原数值应该为(MOD-1);
AC代码
Accepted | 4704 | 31MS | 856K | 893 B | C++ |
1 #include<cstdio> 2 #include<iostream> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 #define MAXSIZE 1000000 8 #define MOD 1000000007 9 typedef __int64 ll; 10 struct hp 11 { 12 int len; 13 int s[MAXSIZE+10]; 14 }; 15 string n; 16 hp pows; 17 void input(hp &a, string str) 18 { 19 while(str[0]=='0'&&str.size()>1) 20 str.erase(0, 1); 21 int len=str.size(); 22 a.len=len; 23 for(int i=1;i<=len;i++) 24 a.s[i]=str[i-1]-'0'; 25 } 26 int devide(const hp &a, ll b) 27 { 28 ll d=0; 29 int len=a.len; 30 for(int i=1;i<=len;i++) 31 { 32 d=d*10+a.s[i]; 33 d%=b; 34 } 35 if(d==0)return MOD-2; 36 else return d-1; 37 } 38 int quickpow(ll a, ll b) 39 { 40 int ret=1; 41 while(b) 42 { 43 if(b&1) 44 ret=(ret*a)%MOD; 45 b>>=1; 46 a=(a*a)%MOD; 47 } 48 return ret; 49 } 50 int main() 51 { 52 while(cin>>n) 53 { 54 input(pows, n); 55 ll p=devide(pows, MOD-1); 56 ll ans=quickpow(2, p); 57 printf("%I64d\n", ans); 58 } 59 return 0; 60 }
---恢复内容结束---