洛咕 P3704 [SDOI2017]數字表格
阿新 • • 發佈:2018-12-07
大力推式子
現根據套路列舉\(\gcd(i,j)\)
\(ans=\Pi_{x=1}^nfib[x]^{\sum_{i=1}^{n/x}\sum_{j=1}^{n/x}[\gcd(i,j)=1]}\)
莫比烏斯反演
\(ans=\Pi_{x=1}^nfib[x]^{\sum_{i=1}^{n/x}\mu(i)(n/ix)(m/ix)}\)
把列舉\(i\)提出來,改成列舉\(ix\),裡面還是列舉\(x\)
\(ans=\Pi_{i=1}^n\Pi_{x|i}fib[x]^{\mu(i/x)(n/i)(m/i)}\)
有一個\((n/i)(m/i)\),這個明顯可以數論分塊,但那個\(\mu(i/x)\)
\(ans=\Pi_{i=1}^n(\Pi_{x|i}fib[x]^{\mu(i/x)})^{(n/i)(m/i)}\)
就可以預處理\(f[i]=(\Pi_{x|i}fib[x]^{\mu(i/x)})\)了
#include<bits/stdc++.h> #define il inline #define vd void #define mod 1000000007 #define Mod 1000000006 typedef long long ll; il int gi(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int pri[1000010],pr,mu[1000010],yes[1000010]; int fib[1000010],ifib[1000010]; int f[1000010],g[1000010]; il int Pow(int x,int y){ int ret=1; while(y){ if(y&1)ret=1ll*ret*x%mod; x=1ll*x*x%mod;y>>=1; } return ret; } int main(){ mu[1]=1; for(int i=2;i<=1000000;++i){ if(!yes[i])mu[i]=-1,pri[++pr]=i; for(int j=1;i*pri[j]<=1000000&&j<=pr;++j){ yes[i*pri[j]]=1; if(i%pri[j]==0){mu[i*pri[j]]=0;break;} mu[i*pri[j]]=-mu[i]; } } fib[1]=1;for(int i=2;i<=1000000;++i)fib[i]=(fib[i-1]+fib[i-2])%mod; for(int i=1;i<=1000000;++i)ifib[i]=Pow(fib[i],mod-2); for(int i=1;i<=1000000;++i)f[i]=1; for(int i=1;i<=1000000;++i) for(int j=i;j<=1000000;j+=i) if(mu[j/i]==1)f[j]=1ll*f[j]*fib[i]%mod; else if(mu[j/i]==-1)f[j]=1ll*f[j]*ifib[i]%mod; for(int i=2;i<=1000000;++i)f[i]=1ll*f[i-1]*f[i]%mod; g[0]=1;for(int i=1;i<=1000000;++i)g[i]=Pow(f[i],mod-2); int T=gi(),n,m,ans; while(T--){ n=gi(),m=gi(); if(n>m)std::swap(n,m); ans=1; for(int i=1;i<=n;++i){ int j=std::min(n/(n/i),m/(m/i)); ans=1ll*ans*Pow(1ll*f[j]*g[i-1]%mod,(int)(1ll*(n/i)*(m/i)%Mod))%mod; i=j; } printf("%d\n",ans); } return 0; }