【SDOI 2010】古代猪文

Posted by WHZ0325 on 2019-04-18, Viewed times

题目描述

给定两个整数 $n,g$,求 $g^{\sum_{k|n}C_n^k}\mod 999911659$ 的值。$1\le n,g\le 10^9$。

算法分析

当 $g$ 与模数 $999911659$ 互质时,根据欧拉定理得 $g^{\sum_{k|n}C_n^k}\mod 999911659=g^{\sum_{k|n}C_n^k\mod 999911658}\mod 999911659$,问题转化为求 $\sum_{k|n}C_n^k\mod 999911658$ 的值;若不互质,由于模数是质数,当且仅当 $g$ 是它倍数,此时答案为 $0$。

$O(\sqrt{n})$ 枚举约数 $k$,将 $999911658$ 分解质因数得 $999911658=2\times 3\times 4679\times 35617$,可以利用 Lucas 定理算出组合数模每个质因子得到的结果,列出同余方程后用中国剩余定理求解即可。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <cstdio>
typedef long long int ll;
const int mod=999911658;
const int pri[4]={2,3,4679,35617};
inline int qpow(int n,int k,int p) {
int ans=1;
while(k) {
if(k&1) ans=(ll)ans*n%p;
n=(ll)n*n%p;k>>=1;
}
return ans;
}
int pre[40005][4],inv[40005][4];
inline void exgcd(int a,int b,int &x,int &y) {
if(!b) {x=1;y=0;}
else {exgcd(b,a%b,y,x);y-=a/b*x;}
}
int Lucas(int n,int k,int id) {
if(k>n) return 0;
else if(!k||n==k) return 1;
else if(n<pri[id]&&k<pri[id]) return (ll)pre[n][id]*inv[n-k][id]%pri[id]*inv[k][id]%pri[id];
return (ll)Lucas(n/pri[id],k/pri[id],id)*Lucas(n%pri[id],k%pri[id],id)%pri[id];
}
int n,g;
inline int ExLucas(int k) {
int ans=0;
for(register int j=0;j<4;++j) {
int x,y;exgcd(mod/pri[j],pri[j],x,y);x=(x%pri[j]+pri[j])%pri[j];
ans=(ans+(ll)Lucas(n,k,j)*x%mod*(mod/pri[j])%mod)%mod;
}
return ans;
}
int main() {
scanf("%d%d",&n,&g);
if(g==999911659) {puts("0");return 0;}
for(register int j=0;j<4;++j) pre[0][j]=inv[0][j]=1;
for(register int i=1;i<=35617;++i) {
for(register int j=0;j<4;++j) {
pre[i][j]=(ll)pre[i-1][j]*i%pri[j];
inv[i][j]=qpow(pre[i][j],pri[j]-2,pri[j]);
}
}
int ans=0;
for(register int i=1;i*i<=n;++i) if(n%i==0) {
ans=(ans+ExLucas(i))%mod;
if(i*i!=n) ans=(ans+ExLucas(n/i))%mod;
}
printf("%d\n",qpow(g,ans,999911659));
return 0;
}