[SDOI2010]古代猪文

洛咕

题意:求\(m^{\sum{d|n\ C_n^d}}\ mod\ 999911659\)

分析:因为\(999911659\)是质数,则由欧拉定理的推论得\(m^{\sum{d|n\ C_n^d\ mod\ 999911658}}\ mod\ 999911659\)

因为\(m^{\sum{d|n\ C_n^d\ mod\ 999911658}}\)直接\(Lucas\)还是会爆,考虑将\(999911658\)质因数分解为\(2*3*4679*35617\),则可以运用\(Lucas\)定理分别求出\(\sum {d|n\ C_n^d} \mod 2/3/4679/35617\),记为\(b_1,b_2,b_3,b_4\)

然后考虑合并.我们现在得到这样一个式子:

\(\left\{\begin{aligned}x\equiv\ b_1(\mod 2) \quad\\ x\equiv\ b_2(\mod 3) \quad\\ x\equiv\ b_3(\mod 4679) \quad\\x\equiv\ b_4(\mod 35617) \quad\end{aligned}\right.\)

直接中国剩余定理求解\(x\)就行了.最后输出\(m^x \mod 999911658\)

综上我们需要用到Lucas定理(包括组合数,阶乘,逆元),中国剩余定理(包括扩欧)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
    LL s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
const LL mod=999911659;
LL n,m,ans,tot;
int prime[5]={0,2,3,4679,35617};
LL a[50005],b[5],jc[50005];
inline LL ksm(int a,int b,int c){
    LL cnt=1;
    while(b){
    	if(b&1)cnt=(1LL*cnt*a)%c;
    	a=(1LL*a*a)%c;
    	b>>=1;
    }
    return cnt;
}
inline void get_jc(int p){//计算组合数要用到阶乘
    jc[0]=1;
    for(int i=1;i<=p;i++)
    	jc[i]=(jc[i-1]*i)%p;
}
inline LL C(int n,int m,int p){//计算组合数
    if(n<0||m<0||n<m)return 0;
    return ((1LL*jc[n]*ksm(jc[m],p-2,p))%p*ksm(jc[n-m],p-2,p))%p;
//直接根据费马小定理 用快速幂算逆元
}
inline LL Lucas(int n,int m,int p){//Lucas模板
    if(n<m)return 0;else if(n==0||m==0)return 1;
    return (1LL*C(n%p,m%p,p)*Lucas(n/p,m/p,p))%p;
}
inline int exgcd(int a,int b,int &x,int &y){
    if(b==0){x=1;y=0;return a;}
    int d=exgcd(b,a%b,y,x);
    y-=x*(a/b);
    return d;
}//中国剩余定理要用到扩欧
inline void Intchina(){//中国剩余定理模板
    LL M=1;
    for(int i=1;i<=4;i++)M*=prime[i];
    for(int i=1;i<=4;i++){
    	int Mi=M/prime[i],x,y;
    	exgcd(Mi,prime[i],x,y);
    	ans=((ans+Mi*x*b[i])%M+M)%M;
    }
}
int main(){
    n=read();m=read();
    if(m%mod==0){puts("0");return 0;}//一定要特判
    for(int i=1;i*i<=n;i++){//枚举n的所有约数
    	if(n%i==0){
	    	a[++tot]=i;
	    	if(i*i!=n)a[++tot]=n/i;
        }
    }
//分别计算mod 2 3 4679 35617的值
    for(int i=1;i<=4;i++){
    	get_jc(prime[i]);
    	for(int j=1;j<=tot;j++)
	    b[i]=(b[i]+Lucas(n,a[j],prime[i]))%prime[i];
    }
    Intchina();//合并
    printf("%lld\n",ksm(m,ans,mod));
    return 0;
}

posted on 2019-03-30 17:22  PPXppx  阅读(122)  评论(0编辑  收藏  举报