Link
Description
对于斐波那契 (F)。(T) 次询问,每次给定 (n) 和 (m) ,求
[prod_{i=1}^n prod_{j=1}^m F_{gcd(i,j)}
]
Solution
一开始就很蠢地把 (F_{gcd(i,j)}) 拆成 (gcd(F_{i},F_{j}))。虽然确实有这个结论,但是显然推不下去,而又没有考虑回溯……服了
其实不拆的话相当好推,就常规套路就行了。令 (c=min(n,m))
[egin{align}
(*)=prod_{d=1}^c F_d^{sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=d]}
end{align}
]
然后立即发现右上角是一个熟悉得不能再熟悉的式子,直接跳过中间步骤,得到
[egin{align}
(1)&=prod_{d=1}^c F_d^{sum_{k=1}^{lfloor frac{n}{d}
floor} mu(k)lfloor frac{n}{kd}
floorlfloor frac{m}{kd}
floor} \
&=prod_{T=1}^c prod_{d|T} F_d^{mu(frac{T}{d})lfloor frac{n}{T}
floorlfloor frac{m}{T}
floor} \
&=prod_{T=1}^c Big(prod_{d|T} F_d^{mu(frac{T}{d})} Big)^{lfloor frac{n}{T}
floorlfloor frac{m}{T}
floor}
end{align}
]
随便处理一下,复杂度 (O(Tsqrt nlog n+n log n)),但好像我的跑得很慢?
#include<stdio.h>
#define Mod p
#define ll long long
#define N 1000007
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
int p=(1e9)+7;
ll qpow(ll x,ll y){
ll ret=1,cnt=0;
while(y>=(1ll<<cnt)){
if(y&(1ll<<cnt)) ret=ret*x%p;
x=x*x%p,cnt++;
}
return ret;
}
ll f[N][3],g[N];
int mu[N],P[N],cnt=0;
bool mk[N];
inline int min(int x,int y){return x<y? x:y;}
int main(){
f[0][2]=0,f[1][2]=1;
for(int i=2;i<N;i++) f[i][2]=(f[i-1][2]+f[i-2][2])%Mod;
for(int i=0;i<N;i++) f[i][0]=qpow(f[i][2],p-2);
mu[1]=1;
for(int i=2;i<N;i++){
if(!mk[i])
P[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&P[j]*i<N;j++){
mk[i*P[j]]=1;
if(i%P[j]) mu[i*P[j]]=-mu[i];
else break;
}
}
for(int i=0;i<N;i++) g[i]=f[i][1]=1;
for(int i=1;i<N;i++)
for(int j=1;j*i<N;j++)
g[i*j]=g[i*j]*f[i][mu[j]+1]%Mod;
for(int i=2;i<N;i++) g[i]=g[i]*g[i-1]%Mod;
int T=read();
while(T--){
int n=read(),m=read();
int rg=min(n,m);
ll ans=1;
for(int l=1,r;l<=rg;l=r+1){
r=min(n/(n/l),m/(m/l));
ans=ans*qpow(g[r]*qpow(g[l-1],p-2)%p,1ll*(n/l)*(m/l))%p;
}
printf("%lld
",ans);
}
}