题面
多组数据,每组数据给定 n,m,求:
i=1∏nj=1∏mfibgcd(i,j)
其中 fibi 表示斐波那契第 i 项,fib1=fib2=1。
n,m≤106,T≤103。
题解
不失一般性,设 n<m。
不妨考虑数列第 i 项能产生多少贡献,答案可以写为:
k=1∏nfibi∑i=0n∑j=0m[gcd(i,j)=k]
先把指数提出来处理一下:
i=0∑nj=0∑m[gcd(i,j)=k]
莫反老套路了吧,中间过程省略:
d=1∏⌊kn⌋μ(d)⌊kdn⌋⌊kdm⌋
带回去:
k=1∏nfibk∑d=1⌊kn⌋μ(d)⌊kdn⌋⌊kdm⌋
然后考虑把指数整理一下:
k=1∏n(fibk∑d=1⌊kn⌋μ(d))⌊kdn⌋⌊kdm⌋
里面的内容,实际上就是 ∑d=1⌊kn⌋μ(d) 这么多个 fibk 相乘,莫反老套路,设 p=kd:
k=1∏n⎝⎜⎛k∣p∏fibkμ(kp)⎠⎟⎞⌊pn⌋⌊pm⌋
分别考虑括号内和括号外,对于括号外,数论分块即可。
括号内的东西,设:
f(n)=k∣n∏fibkμ(kn)
直接暴力预处理,用埃式筛即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include<bits/stdc++.h> #define int long long using namespace std; const int max_n=1000006,N=1000000,mod=1000000007; inline int read(){ int x=0;bool w=0;char c=getchar(); while(c<'0' || c>'9') w|=c=='-',c=getchar(); while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return w?-x:x; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); } inline int mi(int a,int p=mod-2){ int res=1; while(p){ if(p&1) res*=a,res%=mod; a*=a,a%=mod,p>>=1; } return res; }
int n,m,f[max_n],fib[max_n],iv[max_n];
bool isp[max_n]; int pr[max_n],cnt,mu[max_n]; inline void init(int n){ memset(isp,1,sizeof(isp)),isp[1]=0,mu[1]=1; fib[1]=fib[2]=iv[1]=iv[2]=1; for(register int i=3;i<=n;++i) fib[i]=(fib[i-1]+fib[i-2])%mod, iv[i]=mi(fib[i]); for(register int i=2;i<=n;++i){ if(isp[i]){ pr[++cnt]=i, mu[i]=-1; } for(register int j=1;j<=cnt && i*pr[j]<=n;++j){ isp[i*pr[j]]=0; if(i%pr[j]==0){ mu[i*pr[j]]=0; break; } mu[i*pr[j]]=-mu[i]; } } for(register int i=0;i<=n;++i) f[i]=1; for(register int i=1;i<=n;++i) if(mu[i]) for(register int j=i;j<=n;j+=i) f[j]=f[j]*(mu[i]>0?fib[j/i]:iv[j/i])%mod; for(register int i=2;i<=n;++i) f[i]=f[i]*f[i-1]%mod; }
signed main(){ init(N); for(register int T=read();T>0;--T){ n=read(),m=read(); if(n>m) n^=m^=n^=m; int ans=1; for(register int l=1,r;l<=n;l=r+1){ r=min(n/(n/l),m/(m/l)); int tmp=f[r]*mi(f[l-1])%mod; ans=ans*mi(tmp,(n/l)*(m/l)%(mod-1))%mod; } write((ans+mod)%mod),putchar('\n'); } return 0; }
|