标签:des href 注意 online 数字 组合数 社会 学校 poi
10%的数据中,1 <= N <= 50;
20%的数据中,1 <= N <= 1000;
40%的数据中,1 <= N <= 100000;
100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。
传说中的数论板子大合集,题面是真的好笑;
费马小定理+CRT+lucas+快速幂+逆元+组合数,大概也就这么点吧;
题目要求mod p;
考虑幂很大我们用欧拉降幂:
a^b mod p =a^(b%phi(p)) mod p;
使用的条件是a,p互质且p为质数,这个是用费马小定理搞的;
当a,p互质且p为质数,a^p mod p=a,所以a^(p-1) mod p=1;
所以a^b mod p= a^(b mod (p-1)) mod p;
用欧拉降幂的话phi(p)=p-1,所以是一样的;
然后问题的关键在于求:
n有1e9,所以要用lucas求大组合数:
lucas定理:
然后模数不是质数,那么我们考虑常用的方法对每个质因子求一遍然后最后用CRT合并;
因为只有一次询问,那么我们用sqrt(n)的复杂度枚举n的每个因子,加到四个模线性方程组中,最后用CRT算出来;
记得注意各个部分的模数不同,lucas和算组合数的时候用prime,CRT的时候用p-1,最后快速幂的时候用p;
//MADE BY QT666 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=100050; const int Mod=999911659; int prime[]={2,3,4679,35617}; int n,g; ll Ans,sum[N]; ll qpow(ll x,ll y,ll mo){ ll ret=1; while(y){ if(y&1) (ret*=x)%=mo; (x*=x)%=mo;y>>=1; } return ret; } ll jc[10][N]; ll C(int n,int m,int x){ if(n<m) return 0; return jc[x][n]*qpow(jc[x][m],prime[x]-2,prime[x])%prime[x]*qpow(jc[x][n-m],prime[x]-2,prime[x])%prime[x]; } ll lucas(int n,int m,int x){ if(m==0) return 1; return C(n%prime[x],m%prime[x],x)*lucas(n/prime[x],m/prime[x],x)%prime[x]; } void Crt(){ for(int i=0;i<4;i++){ ll M=(Mod-1)/prime[i]; (Ans+=sum[i]*M%(Mod-1)*qpow(M,prime[i]-2,prime[i])%(Mod-1))%=(Mod-1); } } void work(int d){ for(int i=0;i<4;i++) (sum[i]+=lucas(n,d,i))%=prime[i]; } int main(){ scanf("%d%d",&n,&g);if(g==999911659) {puts("0");return 0;} for(int i=0;i<4;i++){ jc[i][0]=1; for(int j=1;j<=50000;j++) jc[i][j]=(jc[i][j-1]*j)%prime[i]; } g%=Mod; for(int i=1;i*i<=n;i++){ if(n%i==0){ if(i*i==n) work(i); else work(i),work(n/i); } } Crt(); printf("%lld\n",qpow(g,Ans,Mod)); return 0; }
标签:des href 注意 online 数字 组合数 社会 学校 poi
原文地址:http://www.cnblogs.com/qt666/p/7632813.html