bzoj1951 [Sdoi2010]古代猪文 ——数论综合
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1951
题意就是要求 G^( ∑(k|n) C(n,k) ) % p,用费马小定理处理指数,卢卡斯定理处理大组合数,取模用中国剩余定理合并;
好想难写的感觉(其实也不难写?);
关于中国剩余定理,可以看这篇博客:https://www.cnblogs.com/MashiroSky/p/5918158.html
第一次写中国剩余定理合并模数,还有一点好不容易理解的地方,写在注释里。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll n,g,p=999911659,t[4]={2,3,4679,35617},r[5],fac[5][40005]; ll pw(ll a,int b,int mod) { // a%=mod;//可有可无 ll ret=1; for(;b;b>>=1,(a*=a)%=mod) if(b&1) (ret*=a)%=mod; return ret; } ll C(int n,int m,int k) { if(n<m)return 0; return (fac[k][n]*pw(fac[k][m]*fac[k][n-m],t[k]-2,t[k]))%t[k]; } ll Lucas(ll n,ll m,int k) { if(m==0)return 1;//! return (C(n%t[k],m%t[k],k)*Lucas(n/t[k],m/t[k],k))%t[k]; } void exgcd(ll a,ll b,ll &x,ll &y) { if(b==0){x=1; y=0; return;} exgcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; } int CRT() { ll M=t[0],R=r[0],x,y; for(int i=1;i<4;i++) { exgcd(M,t[i],x,y); x=((r[i]-R)%t[i]*x%t[i]+t[i])%t[i];//%t[i]!(CRT取通解方法) //不能是R-r[i]!因为求到的x对于r[i]-R来说是正的,否则需要取一下负 R+=M*x; M*=t[i]; } return R; } int main() { scanf("%lld%lld",&n,&g); if(g==p)//!!! { printf("0"); return 0; } for(int i=0;i<4;i++) { fac[i][0]=1; for(int j=1;j<=t[i];j++) fac[i][j]=(fac[i][j-1]*j)%t[i]; } for(int j=0;j<4;j++) for(int i=1;i*i<=n;i++)//1 if(n%i==0) { (r[j]+=Lucas(n,i,j))%=t[j]; if(i*i!=n) (r[j]+=Lucas(n,n/i,j))%=t[j]; } int ans=CRT(); printf("%lld",pw(g,ans,p)); return 0; }