G39 莫比乌斯反演

视频链接:https://www.bilibili.com/video/BV1Ye4y1j7u9/

 Luogu P1829 [国家集训队]Crash的数字表格

#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));
}

 Luogu P3704 [SDOI2017]数字表格

#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));
  }
}

 

posted @ 2022-12-12 22:35  董晓  阅读(361)  评论(0编辑  收藏  举报