BZOJ 1951 [SDOI2010]古代猪文 (组合数学+欧拉降幂+中国剩余定理)

时间:2023-03-08 20:41:23

题目大意:求$G^{\sum_{m|n} C_{n}^{m}}\;mod\;999911659\;$的值$(n,g<=10^{9})$

并没有想到欧拉定理..

999911659是一个质数,所以$\varphi(p)=p-1$

利用欧拉定理,降幂化简式子$G^{\sum_{m|n} C_{n}^{m}\;mod\;\varphi(p)}$

这样,指数部分可以用$Lucas$+中国剩余定理求解

然而..$G>10^9$很大,可能和模数$999911659$不互质!所以质数要额外加上$\varphi(p)$

 #include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 10100
#define ull unsigned long long
#define ll long long
#define maxn 36000
using namespace std; ll n,g;
const ll m[]={,,,}; ll qpow(ll x,ll y,const ll &mod){
ll ans=;
while(y){
if(y&) ans=(ans*x)%mod;
x=(x*x)%mod,y>>=;
}return ans;
}
namespace excrt{
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b) {x=,y=;return a;}
ll ans=exgcd(b,a%b,x,y);
ll t=x;x=y,y=t-a/b*y;
return ans;
}
ll qadd(ll x,ll y,const ll &mod){
ll ans=;
while(y){
if(y&) ans=(ans+x)%mod;
x=(x+x)%mod,y>>=;
}return ans;
}
ll ans=,M=;
void insert(ll A,ll B)
{
ll a=A,b=B,c=(a-ans%b+b)%b,x,y,g;
g=exgcd(M,b,x,y);b/=g;
//if(c/g!=0) return;
//x=qadd(x,c/g,b);
x=x*(c/g)%b;
ans+=x*M,M*=b,ans=(ans%M+M)%M;
}
};
int son[N],d[N],ps[N],num,cnt;
namespace calc{
ll mul[maxn+],inv[maxn+],minv[maxn+];
void Pre(const ll &mo)
{
mul[]=mul[]=inv[]=inv[]=minv[]=minv[]=;
for(int i=;i<mo;i++){
mul[i]=mul[i-]*i%mo;
inv[i]=1ll*(mo-mo/i)*inv[mo%i]%mo;
minv[i]=minv[i-]*inv[i]%mo;
}
}
ll C(ll a,ll b,const ll &mo)
{return mul[a]*minv[b]%mo*minv[a-b]%mo;}
ll Lucas(ll a,ll b,const ll &mo)
{
if(b>a) return ;
if(a<mo&&b<mo) return C(a,b,mo);
return Lucas(a/mo,b/mo,mo)*Lucas(a%mo,b%mo,mo)%mo;
}
ll solve(const ll &mo)
{
for(int i=;i<mo;i++)
mul[i]=inv[i]=minv[i]=;
Pre(mo);ll ans=;
for(int i=;i<=cnt;i++)
(ans+=Lucas(n,son[i],mo))%=mo;
return ans;
}
};
void dfs_son(int i,ll s)
{
if(i>num) {son[++cnt]=s;return;}
for(int j=;j<=d[i];j++)
dfs_son(i+,s),s*=ps[i];
}
void get_son(ll a)
{
int sq=sqrt(a);
for(int i=;i<=sq;i++)
if(a%i==){
ps[++num]=i;
while(a%i==)
d[num]++,a/=i;
}
if(a!=)
ps[++num]=a,d[num]++;
dfs_son(,);
}
const ll smod=; int main()
{
scanf("%lld%lld",&n,&g);
get_son(n);
for(int i=;i<;i++)
{
ll ans=calc::solve(m[i]);
excrt::insert(ans,m[i]);
}
ll pw=excrt::ans;
ll ans=qpow(g,pw+smod-,smod);
printf("%lld\n",ans);
return ;
}