hdu 4704 Sum (整數和分解+快速冪+費馬小定理降冪)
題意:
給n(1<n<),求(s1+s2+s3+...+sn)mod(1e9+7)。其中si表示n由i個數相加而成的種數,如n=4,則s1=1,s2=3。 (全題文末)
知識點:
整數n有種和分解方法。
費馬小定理:p是質數,若p不能整除a,則 a^(p-1) ≡1(mod p)。可利用費馬小定理降素數冪。
當m為素數,(m必須是素數才能用費馬小定理)
a=2時。(a=2只是題中條件,a可以為其他值)
mod m = * // k=
= //==1為費馬小定理的應用
例如,設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;
題解:
題目相當於求n的分解種數。例如,n=x1+x2+x3+..xk是一種分解,把xi看成由xi個1組成,同理n即為n個1組成。
題目也就是給n個1分組的方法數(這不是類似於組合數學的小球間隔板問題嗎)。每兩個1之間是否放隔板,有放和不放兩種選擇,一共n-1個可選擇間隔。so 總方法數為 。
由於n太大,不好處理啊。
指數太大,發現m=1e9+7為素數,則可用費馬小定理(a^(p-1))≡1(mod p))降冪。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int mod=1e9+7,N=1e5+5; char a[N]; LL quick_mod(LL a,LL p) //快速冪 (快速冪利用了二分思想和秦九昭演算法) { LL ans=1; while(p) { if(p&1) ans=ans*a%mod; a=a*a%mod; p>>=1; } return ans; } int main() { while(~scanf("%s",a)) { int len=strlen(a); LL ans=0; for(int i=0;i<len;i++) { ans=(ans*10+a[i]-'0')%(mod-1); } ans=(ans-1+mod-1)%(mod-1); printf("%lld\n",quick_mod(2,ans)); } return 0; }
這道題還可以找迴圈結。
發現 2^500000003 = 1 = 2^0,所以n=(n-1)%500000003,所以 2^(n - 1) = 2^((n-1)%(mod -1))%mod; (mod-1=500000003)
Sum
Time Limit:1000MS Memory Limit:131072KB 64bit IO Format:%I64d & %I64u
Submit Status
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.
#include <bits/stdc++.h> using namespace std; long long M=1e9+7; /* 題意: S(k)是x1+x2+..+xk=N的組合數 求(S(1)+S(2)+..+S(N))mod 10^9的個數 題解: 注:在這裡1+2+1=4 和 1+1+2=4 屬於不同的方案數 1.求解S(k): 將整數m拆分為n個數字的有序拆分方案數為C(m-1,n-1)(這個是二項式係數) 隔板法理解: 把N分成一份的分法數為C(1,n-1), 把N分成兩份的分法數為C(2,n-1), 把N分成三份的分法數為C(3,n-1), .... , 把N分成N份的分法數為C(n-1,n-1)。 2.求解S(1)+S(2)+..+S(n) = C(0,n-1)+C(1,n-2)+..+C(n-1,n-1) = 2^n-1 為什麼這樣?二項式定理 可以理解成2^(n-1)=(1+1)^(n-1)展開 3.變成求解2^(n-1) mod 10^9, 4. 因為N比較大,所以可以用費馬小定理(假如a,p互質,則a^(p-1)%p == 1恆成立)化簡下 我們可以把n分解。變成t個(p-1)+m。也就是(t*(p-1)+m) %p。 費馬小定理:2^(p-1)%p正好等於1,那就是t個1,乘上一個數沒有影響,所以只剩下2^m % p 所以可以寫成:2^n%p=2^(n%(p-1))%p 而 n%(p-1)=m */ long long quick(long long a,long long n) { long long sum=1; while(n) { if(n&1) { sum=(sum*a)%M; } a=a*a%M; n>>=1; } return sum; } int main() { long long n; char s[100005]; while(cin>>s) { n=0; int len=strlen(s); for(int i=0;i<len;i++) n=(n*10+s[i]-'0')%(M-1); cout<<quick(2,n-1)<<endl; } return 0; } |