題目
分析
初步變形
這道題其實是求:
和別的莫比烏斯反演題目不同之處在於:它是累乘不是累加
但是轉念一想,底數累乘實際上就是指數的累加,所以我們可以這樣做:
然後對於指數,我們把他拿下來單獨處理:之後就都是套路了
於是答案就是:
這個便可以預處理莫比烏斯函數然後用整出分塊做
但是這個的複雜度是還是過不了
第二步變形
這就涉及另一個套路了:
令:
其中指數的一部分可以用整出分塊,把另一部分拿出來單獨討論:
這是一個關於T的函數,而且可以預處理。
預處理方法就是:枚舉d把加到d的倍數T裏面
不明白的看函數裏面init
代碼
下附AC代碼
#include<bits/stdc++.h>
using namespace std;
int read(){
char s;
int x=0,f=1;
while(s<'0'||s>'9'){
if(s=='-')f=-1;
s=getchar();
}
while(s>='0'&&s<='9'){
x*=10;
x+=s-'0';
s=getchar();
}
return x*f;
}
const long long mod=1e9+7;
const long long N=1e6+5;
long long qpow(long long a,long long b){
if(b==0)return (long long )1;
long long rec=qpow(a,b/2)%mod;
if(b&1)return rec*rec%mod*a%mod;
return rec*rec%mod;
}
long long fib[N];//斐波那契數列
long long g[N];//fib的逆元
bool flag[N];
int p[N],pn;
long long mu[N];
long long F[N];//F[n] = Π_d|n fib(d)^mu(T/d)
void init(int n){
mu[1]=1;
fib[1]=1;
g[1]=1;
F[0]=F[1]=1;
for(int i=2;i<=n;i++){
fib[i]=(fib[i-1]+fib[i-2])%mod;
g[i]=qpow(fib[i],mod-2)%mod;
F[i]=1;
if(!flag[i]){
p[pn++]=i;
mu[i]=-1;
}
for(int j=0;j<pn,p[j]*i<=n;j++){
flag[p[j]*i]=1;
if(i%p[j]==0)break;
else mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++){
if(!mu[i])continue;
for(int j=i;j<=n;j+=i){
if(mu[i]==1){
F[j]*=fib[j/i];
F[j]%=mod;
}
else{
F[j]*=g[j/i];
F[j]%=mod;
}
}
}
for(int i=2;i<=n;i++){
F[i]=F[i-1]*F[i]%mod;
}
}
int main(){
int T=read();
init(N-5);
while(T--){
int n,m;
n=read(),m=read();
if(n>m)swap(n,m);
long long ans=1;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
long long inv=qpow(F[l-1],mod-2);
ans*=qpow((F[r]*inv%mod),(long long)(n/l)*(m/l)%(mod-1))%mod;
ans%=mod;
}
ans=(ans+mod)%mod;
printf("%lld\n",ans);
}
}
心得總結
這道題除了基本套路以外,告訴我們(可能之後這個也是一個套路了):
1.乘積化爲指數和式
2.學會提出一部分可以預處理的函數
3.預處理方式有兩種:1.篩法。2.倍數插入