hdu 4704 sum(費馬小定理+快速冪)
阿新 • • 發佈:2019-01-23
題意:
這題意看了很久。。
s(k)表示的是把n分成k個正整數的和,有多少種分法。
例如:
n=4時,
s(1)=1 4
s(2)=3 1,3 3,1 2,2
s(3)=3 1,1,2 1,2,1 2,1,1
s(4)=1 1,1,1,1
s(1)+s(2)+s(3)+s(4)=1+3+3+1=8
當n=1,2,3,4時,可以分別求出結果為 1,2,4,8
於是推出答案就是2^(n-1)---------------------(為什麼?我也不知道,這個是怎麼推出來的)
思路:題意明白了,就是求2^(n-1) mod(10^9+7)唄。
由於這裡的n非常大,1<=n<10^100000,這裡用簡單的暴力絕對超時啊(10^8就會超時)
那麼,這裡用了兩個優化,一個是費馬小定理 a^(p-1)≡1(mod p),另外就是快速冪加速求冪
這裡稍微演示一下如何利用費馬小定理處理:
(單單用費馬小定理處理仍會超時,因為處理完後,指數最大能達到10^9級別,仍會超時)
程式碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod=1e9+7; void pow(__int64 b){//快速求冪(位操作) __int64 a=2; __int64 ans; ans=1; while(b>0){ if(b&1)//判斷是否為奇數,相當於 if(b%2==1) ans=(ans*a)%mod; a=(a*a)%mod; b=b>>1;//二進位制向右移一位,相當於 b=b/2; } printf("%I64d\n",ans); } int main(){ char str[123456]; __int64 num,i; while(~scanf("%s",str)){ num=0; int len=strlen(str); for(i=0;i<len;i++){ num=( num*10+(str[i]-'0') )% (mod-1);//精華部分 } if(num==0) pow(mod-2);//此時n=mod-1,所以應該求pow(mod-2),而不能求成pow(num-1) else pow(num-1); } return 0; }