【BZOJ1951】[Sdoi2010]古代豬文 Lucas定理+CRT
阿新 • • 發佈:2017-10-15
clas div can 一個 mit inline sdoi2010 span ()
【BZOJ1951】[Sdoi2010]古代豬文
Description
求$X=\sum\limits_{d|n}C_n^d$,$Ans=G^X (\mod 999911659)$。Input
有且僅有一行:兩個數N、G,用一個空格分開。Output
有且僅有一行:一個數,表示答案除以999911659的余數。Sample Input
4 2Sample Output
2048HINT
10%的數據中,1 <= N <= 50;
20%的數據中,1 <= N <= 1000;
40%的數據中,1 <= N <= 100000;
100%的數據中,1 <= G <= 1000000000,1 <= N <= 1000000000。
題解:由於n很小,可以暴力枚舉約數並用Lucas定理計算$C_n^d$的值。但是最後求的是$G^X%P$,所以X要對P-1取模,然而P-1不是質數,所以先分解質因數然後用CRT合並即可。
註意:G=P時費馬小定理不成立。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; ll n,m,G,P,ans; ll v[100000],jc[100000],jcc[100000],ine[100000],A[10]; ll lucas(ll a,ll b) { if(a<b) return 0; if(!b) return 1; if(a<P) return jc[a]*jcc[a-b]%P*jcc[b]%P; return lucas(a%P,b%P)*lucas(a/P,b/P)%P; } ll calc() { ll ret=0; jc[0]=jcc[0]=ine[0]=jc[1]=jcc[1]=ine[1]=1; int i; for(i=2;i<P;i++) jc[i]=jc[i-1]*i%P,ine[i]=P-(P/i)*ine[P%i]%P,jcc[i]=jcc[i-1]*ine[i]%P; for(i=1;i<=m;i++) ret=(ret+lucas(n,v[i]))%P; return ret; } inline ll pm(ll x,ll y,ll mod) { ll z=1; while(y) { if(y&1) z=z*x%mod; x=x*x%mod,y>>=1; } return z; } inline ll work(ll a,ll b,ll c) { return (c*pm(a,b-2,b)%b+b)%b; } int main() { scanf("%lld%lld",&n,&G); if(G==999911659) { printf("0"); return 0; } ll i; for(i=1;i*i<n;i++) if(n%i==0) v[++m]=i,v[++m]=n/i; if(i*i==n) v[++m]=i; P=2,A[1]=calc(); P=3,A[2]=calc(); P=4679,A[3]=calc(); P=35617,A[4]=calc(); P=999911658; ans=(ans+P/2*work(P/2,2,A[1]))%P; ans=(ans+P/3*work(P/3,3,A[2]))%P; ans=(ans+P/4679*work(P/4679,4679,A[3]))%P; ans=(ans+P/35617*work(P/35617,35617,A[4]))%P; printf("%lld",pm(G,(ans+P)%P,P+1)); return 0; }
【BZOJ1951】[Sdoi2010]古代豬文 Lucas定理+CRT