G39 莫比乌斯反演
视频链接:https://www.bilibili.com/video/BV1Ye4y1j7u9/
#include <algorithm> #include <cstdio> using namespace std; const int N=10000010; const int P=20101009; int vis[N],p[N],mu[N],S[N],cnt; void init(){ mu[1]=1; for(int i=2; i<N; ++i){ if(!vis[i])p[++cnt]=i,mu[i]=-1; for(int j=1; i*p[j]<N; ++j){ vis[i*p[j]]=1; if(i%p[j] == 0) break; mu[i*p[j]]=-mu[i]; } } for(int i=1;i<N;++i) S[i]=(S[i-1]+1LL*mu[i]*i*i%P+P)%P; } int G(int n, int m){ return (1LL*n*(n+1)/2%P)*(1LL*m*(m+1)/2%P)%P; } int F(int n, int m){ int res=0; for(int l=1,r; l<=n; l=r+1){ r=min(n/(n/l),m/(m/l)); res=(res+1LL*(S[r]-S[l-1])*G(n/l,m/l)%P+P)%P; } return res; } int calc(int n, int m){ if(n>m) swap(n,m); int res=0; for(int l=1,r; l<=n; l=r+1){ r=min(n/(n/l),m/(m/l)); res=(res+1LL*(r-l+1)*(l+r)/2%P*F(n/l,m/l)%P)%P; } return res; } int main(){ init(); int n,m; scanf("%d%d", &n, &m); printf("%d\n", calc(n,m)); }
#include<iostream> #include<cstdio> #include<cstdlib> using namespace std; #define P 1000000007 #define N 1000010 int mu[N],p[N],vis[N],cnt; int f[N],g[N],F[N]; int qpow(int a,int b){ int res=1; while(b){ if(b&1) res=1ll*res*a%P; a=1ll*a*a%P; b>>=1; } return res; } void init(){ mu[1]=1; for(int i=2;i<N;++i){ if(!vis[i]) p[++cnt]=i, mu[i]=-1; for(int j=1;i*p[j]<N;++j){ vis[i*p[j]]=1; if(i%p[j]==0) break; mu[i*p[j]]=-mu[i]; } } f[1]=g[1]=F[0]=F[1]=1; for(int i=2;i<N;++i){ f[i]=(f[i-1]+f[i-2])%P; g[i]=qpow(f[i],P-2); F[i]=1; } for(int i=1;i<N;++i) for(int j=i;j<N;j+=i) if(mu[j/i]) F[j]=1ll*F[j]*(mu[j/i]==1?f[i]:g[i])%P; for(int i=2;i<N;++i) F[i]=1ll*F[i]*F[i-1]%P; //前缀积 } int calc(int n, int m){ if(n>m) swap(n,m); int r,s,ans=1; for(int l=1;l<=n;l=r+1){ r=min(n/(n/l),m/(m/l)); s=1ll*F[r]*qpow(F[l-1],P-2)%P; //区间积 ans=1ll*ans*qpow(s,1ll*(n/l)*(m/l)%(P-1))%P; } return ans; } int main(){ init(); int T,n,m; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); printf("%d\n",calc(n,m)); } }
#include<iostream> #include<cstdio> #include<cstdlib> using namespace std; #define P 1000000007 #define N 1000010 int mu[N],p[N],vis[N],cnt; int f[N],g[N],F[N]; int qpow(int a,long long b){ int res=1; while(b){ if(b&1) res=1ll*res*a%P; a=1ll*a*a%P; b>>=1; } return res; } void init(){ mu[1]=1; for(int i=2;i<N;++i){ if(!vis[i]) p[++cnt]=i, mu[i]=-1; for(int j=1;i*p[j]<N;++j){ vis[i*p[j]]=1; if(i%p[j]==0) break; mu[i*p[j]]=-mu[i]; } } f[1]=g[1]=F[0]=F[1]=1; for(int i=2;i<N;++i){ f[i]=(f[i-1]+f[i-2])%P; g[i]=qpow(f[i],P-2); F[i]=1; } for(int i=1;i<N;++i) for(int j=i;j<N;j+=i) if(mu[j/i]) F[j]=1ll*F[j]*(mu[j/i]==1?f[i]:g[i])%P; for(int i=2;i<N;++i) F[i]=1ll*F[i]*F[i-1]%P; //前缀积 } int calc(int n, int m){ if(n>m) swap(n,m); int r,s,ans=1; for(int l=1;l<=n;l=r+1){ r=min(n/(n/l),m/(m/l)); s=1ll*F[r]*qpow(F[l-1],P-2)%P; //区间积 ans=1ll*ans*qpow(s,1ll*(n/l)*(m/l))%P; //指数不取模 } return ans; } int main(){ init(); int T,n,m; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); printf("%d\n",calc(n,m)); } }