数字表格
本人第一道数论黑题,虽然有些参照题解,但是颇有收获。
首先可以将问题转化为求一下式子:
\[\prod\limits_{k=1}^nf_k^{\sum\limits_{i=1}^n\mu(i)\left[\frac{n}{ik}\right]\left[\frac{m}{ik}\right]}
\]
显然这个式子是可以分块求解的,但是太慢了。
学到一个套路。令\(T=ik\),调换一下顺序成这样:
\[\prod\limits_{T=1}^n\prod\limits_{d|T}f_d^{\mu(\frac{T}{d})\left[\frac{n}{T}\right]\left[\frac{m}{T}\right]}
\]
发现有些东西可以提出来:
\[\prod\limits_{T=1}^n\left(\prod\limits_{d|T}f_d^{\mu(T/d)}\right)^{\left[\frac{n}{T}\right]\left[\frac{m}{T}\right]}
\]
对于每一个,可以暴力预处理\(\prod\limits_{d|T}f_d^{\mu(T/d)}\),对于整体直接分块就好了!
奉上代码:
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=1e6;
const int mod=1e9+7;
ll f[maxn+10],g[maxn+10];int t,n,m;
int mu[maxn+10],flag[maxn+10],pri[maxn+10],cnt;
inline ll ksm(ll x,ll y){
ll ans=1;
while(y){
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;y>>=1;
}
return ans;
}
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x;
}
signed main(){
g[0]=f[1]=f[2]=1;
for(int i=3;i<=maxn;i++)
f[i]=(f[i-1]+f[i-2])%mod;
mu[1]=1;
for(int i=2;i<=maxn;i++){
if(!flag[i])mu[i]=-1,pri[++cnt]=i;
for(int j=1;j<=cnt&&pri[j]*i<=maxn;j++){
flag[i*pri[j]]=1;
if(i%pri[j]==0){
mu[i*pri[j]]=0;
break;
}
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=maxn;i++)g[i]=1;
for(int i=1;i<=maxn;i++)
for(int j=1;j*i<=maxn;j++){
if(mu[j]==0)continue;
if(f[i]==0)g[i*j]=0;
else if(mu[j]==1)g[i*j]=(g[i*j]*f[i])%mod;
else g[i*j]=(g[i*j]*ksm(f[i],mod-2))%mod;
}
for(int i=2;i<=maxn;i++)
g[i]=(g[i]*g[i-1])%mod;
t=read();
while(t--){
n=read(),m=read();
ll ans=1;
if(n>m)std::swap(n,m);
for(register int l=1,r;l<=n;l=r+1){
r=std::min(n/(n/l),m/(m/l));
ll tot=g[r]*ksm(g[l-1],mod-2)%mod;
ans=(ans*ksm(tot,1ll*(n/l)*(m/l)%(mod-1)))%mod;
//printf("l=%d\n",l);
}
printf("%lld\n",ans);
}
return 0;
}
深深地感到自己的弱小。