[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{egin{aligned}xequiv b_1(mod 2) quad\ xequiv b_2(mod 3) quad\ xequiv b_3(mod 4679) quad\xequiv b_4(mod 35617) quadend{aligned} ight.)

直接中国剩余定理求解(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
",ksm(m,ans,mod));
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10628163.html