问题:
[n/k]/d==[n/(kd)];
线性筛正确性证明
这么求逆元Right?a=k*p;
1LL转化作用域
long long做数组下标
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long Lint; const int maxn=1000009; const int mm=1000000007; int T; Lint n,m; Lint ksm(Lint a,Lint p){ Lint ret=1; for(;p;p>>=1,a=a*a%mm){ if(p&1)ret=ret*a%mm; } return ret; } Lint inv(Lint x){ return ksm(x,mm-2); } Lint g[maxn]; Lint invg[maxn]; Lint prime[maxn]; int vis[maxn],cnt; int mu[maxn]; Lint f[maxn]; int Lineshake(){ vis[1]=1;mu[1]=1; for(int i=2;i<=1000000;++i){ if(!vis[i]){ prime[++cnt]=i; mu[i]=-1; } for(int j=1;(j<=cnt)&&(i*prime[j]<=1000000);++j){ vis[i*prime[j]]=1; if(i%prime[j]==0){ mu[i*prime[j]]=0;break; } mu[i*prime[j]]=-mu[i]; } } f[0]=0;f[1]=1; for(int i=2;i<=1000000;++i)f[i]=(f[i-1]+f[i-2])%mm; for(int i=0;i<=1000000;++i)g[i]=1; for(int d=1;d<=1000000;++d){ Lint invf=inv(f[d]); for(int k=1;k*d<=1000000;++k){ if(mu[k]==1){ g[k*d]=g[k*d]*f[d]%mm; } if(mu[k]==-1){ g[k*d]=g[k*d]*invf%mm; } } } for(int i=1;i<=1000000;++i)g[i]=g[i-1]*g[i]%mm; for(int i=0;i<=1000000;++i)invg[i]=inv(g[i]); } int Init(){ cnt=0; memset(g,0,sizeof(g)); memset(vis,0,sizeof(vis)); } int Getans(){ if(n>m)swap(n,m); Lint ret=1; Lint last; for(int i=1;i<=n;i=last+1){ last=min(n/(n/i),m/(m/i)); ret=ret*ksm(g[last]*invg[i-1]%mm,(n/i)*1LL*(m/i))%mm; } return (int)ret%mm; } int main(){ Init(); Lineshake(); scanf("%d",&T); while(T--){ scanf("%lld%lld",&n,&m); printf("%d\n",Getans()); } return 0; }