传送门:bzoj1951
题解
此题考到的知识点比较多,首先得看出这是个
CRT
C
R
T
。
由欧拉定理,当
n⊥p
n
⊥
p
时,
nϕp≡n (mod p)
n
ϕ
p
≡
n
(
m
o
d
p
)
.
此题即求
G∑d|n(nd)(mod p−1) (mod p)
G
∑
d
|
n
(
n
d
)
(
m
o
d
p
−
1
)
(
m
o
d
p
)
的值。
n≤109
n
≤
10
9
,所以
(nd)
(
n
d
)
可用卢卡斯定理求得:
p为素数时,
(nm)≡(⌊np⌋⌊mp⌋)(n mod pm mod p) (mod p)
(
n
m
)
≡
(
⌊
n
p
⌋
⌊
m
p
⌋
)
(
n
m
o
d
p
m
m
o
d
p
)
(
m
o
d
p
)
还得线性推一下逆元。
这里的
p−1(999911658)
p
−
1
(
999911658
)
不是素数,但它可以拆分成
999911658=2∗3∗4679∗35617
999911658
=
2
∗
3
∗
4679
∗
35617
的形式。这样我们可以对四个素因数分别计算,最后通过
CRT
C
R
T
求得最终在
p−1
p
−
1
模意义下的幂次,再快速幂即可。
CRT
C
R
T
求出的解可以证明,具有唯一性。
CRT
C
R
T
(中国剩余定理):求得满足
x≡a1(mod p1)
x
≡
a
1
(
m
o
d
p
1
)
x≡a2(mod p2)
x
≡
a
2
(
m
o
d
p
2
)
…
x≡an(mod pn)
x
≡
a
n
(
m
o
d
p
n
)
的最小正整数
x
x
。(~
pn
p
n
为两两互不相同的素数)
设
M=∏ni=1pi
M
=
∏
i
=
1
n
p
i
,
Mi=Mpi
M
i
=
M
p
i
,
ti≡M−1i (mod pi)
t
i
≡
M
i
−
1
(
m
o
d
p
i
)
可以得到
x=∑ni=1Mitiai (mod M)
x
=
∑
i
=
1
n
M
i
t
i
a
i
(
m
o
d
M
)
注意:
此题有一种特殊情况,因为欧拉定理只在n,p互质情况下成立,当
n≡0(mod p)
n
≡
0
(
m
o
d
p
)
时,直接输出0即可。(其实求一遍快速幂也不会错,但乘的过程中,默认
00=1
0
0
=
1
,所以会WA一个点,需要特判一下)
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=35620,mod=999911659;
int l[4][N],iv[4][N],p[4]={2,3,4679,35617},m[4];
int n,G;
inline int fp(int a,int b,int mod)
{if(!a) return 0;
int ret=1;for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ret=1ll*ret*a%mod;return ret;}
inline int CRT()
{
int M=mod-1,ans=0,res;
for(int i=0;i<4;++i){
res=1ll*M/p[i]*fp(M/p[i],p[i]-2,p[i])%M*m[i]%M;
ans=(1ll*ans+res)%M;
}
return ans;
}
inline int lucas(int x,int y,int id)
{
if(!y) return 1;
if(x<p[id]){
if(y>x) return 0;
return 1ll*l[id][x]*iv[id][y]%p[id]*iv[id][x-y]%p[id];
}else return 1ll*lucas(x/p[id],y/p[id],id)*lucas(x%p[id],y%p[id],id)%p[id];
}
int main(){
int i,j,k;
scanf("%d%d",&n,&G);G%=mod;
// if(G==0){printf("0\n");return 0;}
for(i=0;i<4;++i) iv[i][0]=l[i][0]=iv[i][1]=1;
for(i=1;i<4;++i)
for(j=1;j<p[i];++j){
l[i][j]=1ll*l[i][j-1]*j%p[i];
if(j>1) iv[i][j]=1ll*(p[i]-p[i]/j)*iv[i][p[i]%j]%p[i];
}
for(i=1;i<4;++i)
for(j=1;j<p[i];++j)
iv[i][j]=1ll*iv[i][j]*iv[i][j-1]%p[i];
for(i=1;i*i<=n;++i){
if(n%i==0){
m[0]=(m[0]+((n|i)==n))%2;
for(j=1;j<4;++j) m[j]=(1ll*m[j]+lucas(n,i,j))%p[j];
if(i*i!=n) {
m[0]=(m[0]+((n|(n/i))==n))%2;
for(j=1;j<4;++j) m[j]=(1ll*m[j]+lucas(n,n/i,j))%p[j];
}
}
}
printf("%d\n",fp(G,CRT(),mod));
}