题解 P2480 [SDOI2010]古代猪文
数论全家桶?
题意描述
简单版:
给定 $g,n(g,n\le10^9)$,求 $g^{\sum_{d\mid n}{C_{n}^{d}}} \mod{999911659} $。
做法
首先根据欧拉定理推出:
$$ g^{\sum_{d\mid n}{C_{n}^{d}}} \equiv g^{\sum_{d\mid n}{C_{n}^{d}}\mod{999911658}} (\bmod{999911659}) $$
所以我们只需要求出 $\sum_{d\mid n}{C_{n}^{d}}\mod{999911658}$ 即可,容易想到用卢卡斯定理。
但是 $999911658$ 显然不是个质数,所以我们将其质因数分解。
$$ 999911659=35617\times4679\times3\times2 $$
于是我们只需要用分解后的质数分别对 $\sum_{d\mid n}{C_{n}^{d}}$ 进行计算,然后再套一遍中国剩余定理即可(当然,你可以也枚举 $\lfloor\frac{ans}{35617}\rfloor$ 的值)。
最后再算一次快速幂即可得到答案。
时间复杂度 $O(\sqrt{n}\log{n}\log{999911659})$。
code
#include<cmath>
#include<iostream>
#define int long long
using namespace std;
int P[5]={999911659,35617,4679,3,2};
int s[1000005],p=1,d[1000005];
int a[15],mod[15],m[15],n,ans,g;
void exgcd(int a,int b,int &x,int &y)
{
if(b==0){x=1;y=0;return;}
exgcd(b,a%b,x,y);
int z=x;x=y,y=z-y*(a/b);
}
int qpow(int x,int y,int P)
{
int ans=1;
for(;y;y>>=1)
{
if(y&1)ans=ans*x%P;
x=x*x%P;
}
return ans;
}
int C(int x,int y,int P){return x>y?0:s[y]*d[y-x]%P*d[x]%P;}
int Lucas(int x,int y,int P)
{
if(y==0)return 1;
return Lucas(x/P,y/P,P)*C(x%P,y%P,P)%P;
}
void work(int k)
{
int mod=P[k];
s[0]=d[0]=1;
for(int i=1;i<mod;i++)
{
s[i]=(s[i-1]*i)%mod;
d[i]=qpow(s[i],mod-2,mod);
}
for(int i=1;i<=sqrt((long long)n);i++)
{
if(!(n%i))
{
a[k]=(a[k]+Lucas(i,n,mod))%mod;
if(i*i==n)continue;
a[k]=(a[k]+Lucas(n/i,n,mod))%mod;
}
}
m[k]=mod;
p*=mod;
}
signed main()
{
scanf("%lld%lld",&n,&g);
if(!(g%P[0]))return!printf("0");
for(int i=1;i<=4;i++)work(i);
for(int i=1;i<=4;i++)
{
mod[i]=p/m[i];
int x=0,y=0;
exgcd(mod[i],m[i],x,y);
ans+=a[i]*mod[i]*(x<0?x+m[i]:x);
ans%=p;
}
printf("%lld",qpow(g,ans,P[0]));
}