标签:
10%的数据中,1 <= N <= 50;
20%的数据中,1 <= N <= 1000;
40%的数据中,1 <= N <= 100000;
100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。
这道题方法很好!
可以发现模数是一个质数,所以由费马小定理,我们只需要求出指数对999911659-1取模的结果。分解质因数,可以发现999911658=2*3*4679*35617。所以我们就可以分别对每个质因数求解,然后用中国剩余定理合并。而对每个质因数求解的问题就是求组合数模一个小质数,预处理+Lucas定理。
P.S.如何O(n)预处理1-n关于p的逆元(n<p)?
我们从小到大依次计算。
对于i,令p=x*i-y(0<y<i),
即 x*i=y(mod p)。
所以i的逆元inv[i]=x*inv[y],而inv[y]已经计算出来了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 100005 using namespace std; const int p[5]={2,3,4679,35617,999911658}; int n,m,fac[maxn],inv[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline ll power(ll x,ll y,ll p) { ll ans=1; for(;y;y>>=1,x=x*x%p) if (y&1) ans=ans*x%p; return ans; } inline void exgcd(ll a,ll b,ll &x,ll &y) { if (!b){x=1;y=0;return;} exgcd(b,a%b,x,y); int t=x;x=y;y=t-a/b*x; } inline ll getinv(ll a,ll b) { ll x,y; exgcd(a,b,x,y); return (x%b+b)%b; } inline int c(int n,int m,int p) { if (n<m) return 0; if (n<p&&m<p) return fac[n]*inv[m]%p*inv[n-m]%p; return c(n/p,m/p,p)*c(n%p,m%p,p)%p; } int main() { n=read();m=read(); ll ans=0; m%=(p[4]+1); if (!m){printf("0\n");return 0;} F(i,0,3) { fac[0]=1; F(j,1,p[i]-1) fac[j]=fac[j-1]*j%p[i]; inv[0]=inv[1]=1; F(j,2,p[i]-1) inv[j]=(p[i]/j+1)*inv[j-p[i]%j]%p[i]; F(j,2,p[i]-1) inv[j]=inv[j-1]*inv[j]%p[i]; ll t1=0,t2=getinv(p[4]/p[i],p[i]); for(int j=1;j*j<=n;j++) if (n%j==0) { (t1+=c(n,j,p[i]))%=p[i]; if (j*j==n) continue; (t1+=c(n,n/j,p[i]))%=p[i]; } (ans+=(ll)p[4]/p[i]%p[4]*t2%p[4]*t1%p[4])%=p[4]; } (ans+=p[4])%=p[4]; cout<<power(m,ans,p[4]+1)<<endl; }
标签:
原文地址:http://blog.csdn.net/aarongzk/article/details/50650492