题目
思路
首先,我们应该转换一下思路
对于每一个\(f_{i}\),我们求出他的贡献是多少
即\(ans=\prod_{d=1}^{n}f(i)^{\sum_{i=1}^{\frac{n}{d}}\sum_{i=1}^{\frac{m}{d}}[gcd(i,j)=1]}\)
首先我们考虑
\(\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)=1]\)
这后面一个就是莫比乌斯反演的老套路了,直接套上\(\mu\)
这里假设\(n>m\)
\(\begin{aligned}\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)=1]&=\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\sum_{k|gcd(i,j)}\mu(k)\\&=\sum_{i=1}^{\frac{n}{d}}\lfloor\frac{n}{id}\rfloor\lfloor\frac{m}{id}\rfloor\mu(i)\end{aligned}\)
这里就可以直接分块了
据某位迟到早退的巨佬表示可以卡过去
设\(t=id\),再带回原式
\(\prod_{t=1}^{n}\prod_{d|t}f(d)^{\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor\mu(\frac{t}{d})}\)
之后我们发现
除了\(\mu(\frac{t}{d})\),剩下两个跟d无关
即我们就可以提出来
\(\prod_{t=1}^{n}(\prod_{d|t}f(d)^{\mu(\frac{t}{d})})^{\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor}\)
内层的可以预处理
时间复杂度为\(\sum_{i=1}^{n}\frac{n}{i}\)
其实这就是调和级数
时间复杂度即为\(O(nlog_n)\)
总时间复杂度为\(O(nlog_n+t\sqrt n*log_n)\)
代码
#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int t;
int n,m;
int lenp;
int mu[1000005];
int pri[1000005];
int inv[1000005];
int r;
long long ans;
long long g[1000005];
long long f[1000005];
bool vis[1000005];
void solve_f()
{
f[0]=0;
f[1]=1;
for(int i=2;i<=1000000;i++)
f[i]=(f[i-1]+f[i-2])%mod;
}
void sieve()
{
mu[1]=1;
for(int i=2;i<=1000000;i++)
{
if(!vis[i])
{
mu[i]=-1;
pri[++lenp]=i;
}
for(int j=1;j<=lenp&&pri[j]*i<=1000000;j++)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0)
{
mu[i*pri[j]]=0;
break;
}
mu[i*pri[j]]=-mu[i];
}
}
}
long long qkpow(long long a,int b)
{
if(b==0)
return 0;
if(b==1)
return a;
long long t=qkpow(a,b/2);
t=t*t%mod;
if(b%2==1)
t=t*a%mod;
return t;
}
void prepare()
{
solve_f();
sieve();
for(int i=0;i<=1000000;i++)
{
g[i]=1;
inv[i]=qkpow(f[i],mod-2);
}
for(int i=1;i<=1000000;i++)
{
for(int j=1;j*i<=1000000;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]*inv[i])%mod;
}
}
for(int j=2;j<=1000000;j++)
g[j]=g[j]*g[j-1]%mod;
}
void c_in()
{
ans=1;
cin>>n>>m;
if(n>m)
swap(n,m);
for(int l=1;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
long long tot=g[r]*qkpow(g[l-1],mod-2)%mod;
ans=ans*qkpow(tot,1ll*(n/l)*(m/l)%(mod-1))%mod;
}
cout<<ans<<'\n';
}
int main()
{
//ios::sync_with_stdio(false);
prepare();
cin>>t;
for(int i=1;i<=t;i++)
c_in();
return 0;
}