这道题真是本人切的第一道黑题,我还是太弱了
题目大意
给定 n,mn,mn,m ,求 ∏i=1n∏j=1mfgcd(i,j)\prod_{i=1}^n\prod_{j=1}^mf_{gcd(i,j)}i=1∏nj=1∏mfgcd(i,j) 其中,fff 为斐波那契数列。
题解
考虑枚举 d=gcd(i,j)d=gcd(i,j)d=gcd(i,j) ,思考会存在多少个 fdf_dfd ,即 ∑i∑j[gcd(i,j)==d]\sum_i\sum_j[gcd(i,j)==d]∑i∑j[gcd(i,j)==d] ,则原式可化为
∏d=1nfd∑i=1n∑j=1m[gcd(i,j)==d]\prod_{d=1}^nf_d^{\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]}d=1∏nfd∑i=1n∑j=1m[gcd(i,j)==d]
观察 ∑i=1n∑j=1m[gcd(i,j)==d]\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d]∑i=1n∑j=1m[gcd(i,j)==d] ,经典莫比乌斯反演,考虑化简,得
∑i=1⌊nd⌋∑j=1⌊md⌋∑k∣gcd(i,j)μ(k)=∑k=1min(⌊nd⌋,⌊md⌋)μ(k)⋅⌊nkd⌋⋅⌊mkd⌋\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{k|gcd(i,j)}\mu(k)\\
=\sum_{k=1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\mu(k)\cdot \lfloor\frac{n}{kd}\rfloor
\cdot\lfloor\frac{m}{kd}\rfloor i=1∑⌊dn⌋j=1∑⌊dm⌋k∣gcd(i,j)∑μ(k)=k=1∑min(⌊dn⌋,⌊dm⌋)μ(k)⋅⌊kdn⌋⋅⌊kdm⌋
接下来设 T=kdT=kdT=kd ,并枚举 TTT ,代入原式得
∏T=1min(n,m)(∏d∣Tfdμ(Td))⌊nT⌋⌊mT⌋\prod_{T=1}^{min(n,m)}(\prod_{d|T}f_{d}^{\mu(\frac{T}{d})})^{\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor}T=1∏min(n,m)(d∣T∏fdμ(dT))⌊Tn⌋⌊Tm⌋
设 F(T)=∏d∣Tfdμ(Td)F(T)=\prod_{d|T}f_{d}^{\mu(\frac{T}{d})}F(T)=∏d∣Tfdμ(dT) , 可以用 O(nlog2n)O(nlog_2n)O(nlog2n) 的时间复杂度将其预处理,然后将指数分块,时间复杂度 O(nlog2n+Tn)O(nlog_2n+T\sqrt n)O(nlog2n+Tn)
Code
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int N=1e6+5;
const ll P=1e9+7;
int n,m,cnt;
int prime[N];
ll mu[N],f[N],g[N],F[N],s[N],Inv[N];
bool bz[N];
ll ksm(ll a,ll b){
ll res=1;
for (;b;b>>=1,a=a*a%P)
if (b&1) res=res*a%P;
return res;
}
void work(){
mu[1]=1;f[0]=0;f[1]=1;g[1]=1;F[1]=1;
for (int i=2;i<=N-5;++i){
if (!bz[i]){
bz[i]=1;
prime[++cnt]=i;
mu[i]=-1;
}
for (int j=1;j<=cnt&&i*prime[j]<=N-5;++j){
bz[i*prime[j]]=1;
if (i%prime[j]) mu[i*prime[j]]=-mu[i];
else break;
}
f[i]=(f[i-1]+f[i-2])%P;
g[i]=ksm(f[i],P-2);
F[i]=1;
}
for (int i=1;i<=N-5;++i){
if (mu[i]==0) continue;
for (int j=i;j<=N-5;j+=i)
F[j]=F[j]*(mu[i]==1?f[j/i]:g[j/i])%P;
}
s[0]=1;Inv[0]=1;
for (int i=1;i<=N-5;++i) s[i]=s[i-1]*F[i]%P;
for (int i=1;i<=N-5;++i) Inv[i]=ksm(s[i],P-2);
return;
}
int main(){
work();
int Q;
scanf("%d",&Q);
ll ans;
while (Q--){
scanf("%d%d",&n,&m);
ans=1;
for (int l=1,r=0;l<=min(n,m);l=r+1){
r=min(n/(n/l),m/(m/l));
ans=ans*ksm(s[r]*Inv[l-1]%P,(ll)(n/l)*(ll)(m/l))%P;
}
printf("%lld\n",ans);
}
return 0;
}