标签:cas images 组合数取模 实现 space 分解 tar ide fine
【算法】欧拉定理+组合数取模(lucas)+中国剩余定理(CRT)
【题解】给定G,N
先考虑简化幂运算,因为模数为素数,由欧拉定理可知G^k=G^(k%φ(p)) mod p,显然G^(k%φ(p)) mod p可以用快速幂求解
此时观察到2p>max(n)>p,所以可能n=p,此时不满足n,p互素,答案直接为0。
对于幂取模部分,因为p是素数,φ(p)=p-1,p-1=999911658=2*3*4679*35617。
由于lucas定理要求p为素数,所以用套路:分开求解后用中国剩余定理合并。
因为p-1分解后无平方因子,所以运算十分方便,若有则需要参考bzoj礼物的方法。
过程中出现的逆元运算均可以用欧拉定理的方法简单实现,因为模数是素数。
最后用中国剩余定理合并即可。
#include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=100010,MOD=999911659;//999911658=2*3*4679*35617 const int p[5]={0,2,3,4679,35617}; ll a[5],fac[5][maxn],n,G; ll power(ll x,ll k,ll p) { if(x==0)return 0; ll ans=1;//快速幂ans=1! while(k>0) { if(k&1)ans=(ans*x)%p;//满足1时才累乘 x=(x*x)%p; k>>=1; } return ans; } ll C(ll n,ll m,ll k) { if(n<m)return 0; return fac[k][n]*power(fac[k][m],p[k]-2,p[k])%p[k]*power(fac[k][n-m],p[k]-2,p[k])%p[k];//n!/m!/(n-m)! } ll lucas(ll n,ll m,ll k) { if(n<m)return 0; if(n<p[k]&&m<p[k])return C(n,m,k); return C(n%p[k],m%p[k],k)*lucas(n/p[k],m/p[k],k)%p[k]; } int main() { scanf("%lld%lld",&n,&G); if(G==MOD) { printf("0"); return 0; } for(int k=1;k<=4;k++) { fac[k][0]=1; for(int i=1;i<p[k];i++)fac[k][i]=fac[k][i-1]*i%p[k];//随时记得取模 } for(int i=1;i*i<=n;i++)if(n%i==0) { int j=n/i; for(int k=1;k<=4;k++) { a[k]=(a[k]+lucas(n,i,k))%p[k]; if(i!=j)a[k]=(a[k]+lucas(n,j,k))%p[k]; } } ll M=MOD-1; ll ans=0; for(int k=1;k<=4;k++)ans=(ans+a[k]*M/p[k]*power(M/p[k],p[k]-2,p[k]))%M; printf("%lld",power(G,ans,MOD)); return 0; }
标签:cas images 组合数取模 实现 space 分解 tar ide fine
原文地址:http://www.cnblogs.com/onioncyc/p/7196029.html