AcWing 213. 古代猪文
考察:欧拉降幂+中国剩余定理+lucas求组合数
思路:
本道题的答案求出幂后快速幂一下即可,所以主要是求幂,由欧拉降幂可知,我们的幂是需要%phi[mod]的.但mod=999911659,是一个质数,mod-1后是一个合数.设此合数为M,我们需要找的就是组合数和%M.但本题直接求组合数会超时,因此考虑lucas求组合数.但lucas需要模数为质数.
这里就涉及到同余的除法定理二, 假设m是n的倍数, (a-b)%m==(a-b)%n,根据这条性质我们可以将M分解质因数.可以发现质因数的最小公倍数刚好==M,分别求出质因数的余数,联立即可求答案.
坑点:
当q = mod时,我们需要特判,否则输出1.
找bug找好久,结果发现是模数写错了....
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 using namespace std; 5 typedef long long ll; 6 const int mod = 999911659,N = 36000,M = 1600; 7 vector<int> v,d; 8 ll fact[4][N],infact[4][N],divs[M]; 9 int n,q; 10 ll qsm(ll a,ll k,ll q) 11 { 12 ll res = 1; 13 while(k) 14 { 15 if(k&1) res = res*a%q; 16 a = a*a%q; 17 k>>=1; 18 } 19 return res; 20 } 21 void inits(int q,int id) 22 { 23 infact[id][0] = fact[id][0] = 1; 24 for(int i=1;i<=q;i++) 25 { 26 fact[id][i] = fact[id][i-1]*i%q; 27 infact[id][i] = infact[id][i-1]*qsm(i,q-2,q)%q; 28 } 29 } 30 ll C(ll a,ll b,int id) 31 { 32 if(a<b) return 0; 33 ll res = fact[id][a]*infact[id][b]%v[id]*infact[id][a-b]%v[id]; 34 return res; 35 } 36 ll lucas(ll a,ll b,int id) 37 { 38 if(a<v[id]&&b<v[id]) return C(a,b,id); 39 return C(a%v[id],b%v[id],id)*lucas(a/v[id],b/v[id],id)%v[id]; 40 } 41 void GetDiv(int n) 42 { 43 for(int i=1;i<=n/i;i++) 44 if(n%i==0) 45 { 46 d.push_back(i); 47 if(i!=n/i) d.push_back(n/i); 48 } 49 } 50 int main() 51 { 52 scanf("%d%d",&n,&q); 53 if(q==N) { printf("0\n"); return 0; } 54 ll ans = 0; 55 v.push_back(2); v.push_back(3); v.push_back(4679); 56 v.push_back(35617); 57 for(int i=0;i<v.size();i++) inits(v[i],i); 58 GetDiv(n); 59 for(int i=0;i<v.size();i++) 60 for(int j=0;j<d.size();j++) 61 divs[i]= (divs[i]+lucas(n,d[j],i))%v[i]; 62 ll M = mod-1; 63 for(int i=0;i<v.size();i++) 64 { 65 ll tmp = mod/v[i]; 66 ll rtmp = qsm(tmp,v[i]-2,v[i]); 67 ans = (ans+divs[i]*tmp%M*rtmp%M)%M; 68 } 69 printf("%lld\n",qsm(q,ans,mod)); 70 return 0; 71 }