给你们讲个笑话:Konoset是个sb,他快速幂的时候把幂次取模了。
原式差不多就是这样吧$prodlimits_{i=1}^{n}prodlimits_{j=1}^{m}f[gcd(i,j)]$
然后我们枚举gcd(i,j)
可以变换一下
$prodlimits_{w=1}^{min(n,m)}f[w]^{sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)==w]}$
然后上面那个玩意搞搞可以反演一下
变为$prodlimits_{w=1}^{min(n,m)}f[w]^{sumlimits_{w|d}mu(frac{d}{w})frac{n}{d}frac{m}{d}}$
上面那个玩意显然=$sumlimits_{d}mu(d)frac{n}{dw}frac{m}{dw}$
然后枚举T=dw
指数变为$sumlimits_{frac{T}{w}}mu(frac{T}{w})frac{n}{T}frac{m}{T}$
然后把上面那个cigma搬到下面来
变成累乘
然后改成枚举T,中间预处理前缀积后面n除以Tm除以T的部分数论分块
这题是真的恶心
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cctype> #define maxn 1000020 #define mod 1000000007 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } long long fib[maxn]; long long sum[maxn]; long long mul[maxn]; long long ni[maxn]; int miu[maxn]; bool vis[maxn]; int prime[maxn],num; long long pow(long long n,long long x){ long long ans=1; while(x){ if(x&1) ans=(ans*n)%mod; n=(n*n)%mod; x>>=1; } return ans; } int main(){ fib[0]=0;fib[1]=vis[0]=vis[1]=miu[1]=1; for(int i=2;i<maxn;++i){ if(vis[i]==0){ prime[++num]=i; miu[i]=-1; } for(int j=1;j<=num&&i*prime[j]<maxn;++j){ vis[i*prime[j]]=1; if(i%prime[j]==0) break; miu[i*prime[j]]=-miu[i]; } } for(int i=2;i<maxn;++i){ fib[i]=(fib[i-1]+fib[i-2])%mod; sum[i]=1; } sum[1]=1; for(int i=1;i<maxn;++i){ long long now=fib[i],ret=pow(now,mod-2); for(register int j=i;j<maxn;j+=i){ if(miu[j/i]==1) sum[j]=(sum[j]*now)%mod; else sum[j]=(sum[j]*ret)%mod; } } mul[1]=sum[1];mul[0]=1;ni[0]=ni[1]=1; for(int i=2;i<maxn;++i){ mul[i]=(sum[i]*mul[i-1])%mod; ni[i]=pow(mul[i],mod-2); } int T=read(); while(T--){ long long n=read(),m=read(); int l=1;long long ans=1;int top=min(n,m); while(l<=top){ int r=min(n/(n/l),m/(m/l)); ans*=pow(mul[r]*ni[l-1]%mod,(n/l)*(m/l)); ans%=mod; l=r+1; } printf("%lld ",ans); } return 0; }