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