Mobius 反演

上次看莫比乌斯繁衍反演是一个月前,讲道理没怎么看懂..

然后出去跪了二十天, 然后今天又开始看发现其实并不难理解

开个这个仅记录一下写过的题。

HAOI 2011 B

这应该是莫比乌斯反演的模板题,有很多题解,不多说。

CODE:

//HAOI 2011 B
//by Cydiater
//2016.7.25
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iomanip>
#include <string>
#include <queue>
#include <map>
using namespace std;
#define ll long long
#define up(i,j,n)       for(int i=j;i<=n;i++)
#define down(i,j,n)     for(int i=j;i>=n;i--)
#define FILE "b"
const int MAXN=5e5+5;
const int oo=0x3f3f3f3f;
inline int read(){
      char ch=getchar();int x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
int prime[MAXN],mu[MAXN],cnt=0,T,a,b,c,d,sum[MAXN],k;
bool vis[MAXN];
namespace solution{
      void make_mu(){
            mu[1]=1;
            memset(vis,0,sizeof(vis));
            up(i,2,50000){
                  if(!vis[i]){prime[++cnt]=i;mu[i]=-1;}
                  for(int j=1;prime[j]*i<=50000&&j<=cnt;j++){
                        vis[prime[j]*i]=1;
                        if(i%prime[j]!=0)mu[i*prime[j]]=-mu[i];
                        else{
                              mu[i*prime[j]]=0;
                              break;
                        }
                  }
            }
            up(i,1,50000)sum[i]=sum[i-1]+mu[i];
      }
      int get(int n,int m){
            if(n>m)swap(n,m);
            int pos,ans=0;
            for(int i=1;i<=n;i=pos+1){
                  pos=min(n/(n/i),m/(m/i));
                  ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i);
            }
            return ans;
      }
}
int main(){
      //freopen("input.in","r",stdin);
      freopen(FILE".in","r",stdin);
      freopen(FILE".out","w",stdout);
      T=read();
      using namespace solution;
      memset(sum,0,sizeof(sum));
      make_mu();
      while(T--){
            a=read();b=read();c=read();d=read();k=read();
            a--;c--;
            a/=k;b/=k;c/=k;d/=k;
            printf("%d\n",get(b,d)-get(a,d)-get(b,c)+get(a,c));
      }
      return 0;
}

BZOJ 1101

上一道题的弱化版..

//BZOJ 1101
//by Cydiater
//2016.7.25
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <map>
#include <iomanip>
using namespace std;
#define ll long long
#define up(i,j,n)       for(int i=j;i<=n;i++)
#define down(i,j,n)     for(int i=j;i>=n;i--)
const int MAXN=5e4+50;
const int oo=0x3f3f3f3f;
inline int read(){
      char ch=getchar();int x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
int mu[MAXN],prime[MAXN],cnt=0,sum[MAXN],T;
bool vis[MAXN];
namespace solution{
      void make_mu(){
            memset(mu,0,sizeof(mu));
            memset(sum,0,sizeof(sum));
            mu[1]=1;
            up(i,2,50000){
                  if(!vis[i]){prime[++cnt]=i;mu[i]=-1;}
                  for(int j=1;j<=cnt&&i*prime[j]<=50000;j++){
                        vis[i*prime[j]]=1;
                        if(i%prime[j]!=0)mu[i*prime[j]]=-mu[i];
                        else{
                              mu[i*prime[j]]=0;
                              break;
                        }
                  }
            }
            up(i,1,50000)sum[i]=sum[i-1]+mu[i];
      }
      int get(int n,int m){
            int pos,ans=0;
            if(n>m)swap(n,m);
            for(int i=1;i<=n;i=pos+1){
                  pos=min(m/(m/i),n/(n/i));
                  ans+=(sum[pos]-sum[i-1])*(m/i)*(n/i);
            }
            return ans;
      }
}
int main(){
      //freopen("input.in","r",stdin);
      using namespace solution;
      make_mu();
      T=read();
      while(T--){
            int a=read(),b=read(),k=read();
            a/=k;b/=k;
            printf("%d\n",get(a,b));
      }
      return 0;
}

Vijos 1889

题意就是让你求出第N个mu[i]!=0的数。

然后我们知道小于 i的莫比乌斯函数值不为0的数有Σmu[i]*(x/i^2)个(我从黄学长博客上看到的QAQ)

然后我们就可以愉快的二分了

PS注意枚举i时要设为ll

//Vijos 1889
//by Cydiater
//2016.7.25
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <queue>
#include <map>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define ll long long
#define up(i,j,n)       for(int i=j;i<=n;i++)
#define down(i,j,n)     for(int i=j;i>=n;i--)
const int MAXN=200000+50;
const int oo=0x3f3f3f3f;
inline ll read(){
      char ch=getchar();ll x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
ll N,prime[MAXN],cnt=0,mu[MAXN],leftt,rightt,mid;
bool vis[MAXN];
namespace solution{
      void make_mu(){
            memset(vis,0,sizeof(vis));
            memset(mu,0,sizeof(mu));
            up(i,2,200000){
                  if(!vis[i]){prime[++cnt]=i;mu[i]=1;}
                  for(int j=1;prime[j]*i<=200000&&j<=cnt;j++){
                        vis[prime[j]*i]=1;
                        if(i%prime[j]!=0)mu[i*prime[j]]=-mu[i];
                        else{
                              mu[i*prime[j]]=0;
                              break;
                        }
                  }
            }
      }
      void init(){
            N=read();
      }
      bool check(ll num){
            ll lim=1LL*sqrt(1.0*num),ans=0;
            for(ll i=2;i<=lim;i++)
            ans+=num/(i*i)*mu[i];
            return ans>=N;
      }
      void slove(){
            leftt=N;rightt=25505460948LL;
            while(leftt+1<rightt){
                  mid=(leftt+rightt)>>1;
                  if(check(mid))    rightt=mid;
                  else              leftt=mid;
            }
            if(check(leftt))cout<<leftt<<endl;
            else            cout<<rightt<<endl;
      }
}
int main(){
      //freopen("input.in","r",stdin);
      //freopen("out.out","w",stdout);
      using namespace solution;
      make_mu();
      init();
      slove();
      return 0;
}

BZOJ 2440

上面那道题做一下小修改就好了

//bzoj2440
//by Cydiater
//2016.7.25
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <queue>
#include <map>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define ll long long
#define up(i,j,n)       for(int i=j;i<=n;i++)
#define down(i,j,n)     for(int i=j;i>=n;i--)
const int MAXN=200000+50;
const int oo=0x3f3f3f3f;
inline ll read(){
      char ch=getchar();ll x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
ll N,prime[MAXN],cnt=0,mu[MAXN],leftt,rightt,mid,T;
bool vis[MAXN];
namespace solution{
      void make_mu(){
            memset(vis,0,sizeof(vis));
            memset(mu,0,sizeof(mu));
            up(i,2,200000){
                  if(!vis[i]){prime[++cnt]=i;mu[i]=1;}
                  for(int j=1;prime[j]*i<=200000&&j<=cnt;j++){
                        vis[prime[j]*i]=1;
                        if(i%prime[j]!=0)mu[i*prime[j]]=-mu[i];
                        else{
                              mu[i*prime[j]]=0;
                              break;
                        }
                  }
            }
      }
      void init(){
            N=read();
      }
      bool check(ll num){
            ll lim=1LL*sqrt(1.0*num),ans=0;
            for(ll i=2;i<=lim;i++)
            ans+=num/(i*i)*mu[i];
            return num-ans>=N;
      }
      void slove(){
            leftt=N;rightt=25505460948LL;
            while(leftt+1<rightt){
                  mid=(leftt+rightt)>>1;
                  if(check(mid))    rightt=mid;
                  else              leftt=mid;
            }
            if(check(leftt))cout<<leftt<<endl;
            else            cout<<rightt<<endl;
      }
}
int main(){
      //freopen("input.in","r",stdin);
      //freopen("out.out","w",stdout);
      using namespace solution;
      make_mu();
      T=read();
      while(T--){
            init();
            slove();
      }
      return 0;
}

YY的GCD

要克服公式恐惧症啊= =

和B那道题很像,但是与那道题不同的是这道题要求求出所有的素数。

设f(p)为在x在1-n中,y在1-m中满足gcd(x,y)==p的个数

所以我们就可以推出这样一个式子:

然后我们就有了暴力求出这个题答案的方法了。

但是显然会超时,考虑优化

这样的话如果我们能预处理出,就能很快的求出答案了。显然暴力的方法能预处理出来。

//YY de GCD
//by Cydiater
//2016.7.26
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <cstdlib>
#include <cstdio>
#include <iomanip>
#include <ctime>
using namespace std;
#define ll long long
#define up(i,j,n)       for(int i=j;i<=n;i++)
#define down(i,j,n)     for(int i=j;i>=n;i--)
#define FILE "YYnoGCD"
const int oo=0x3f3f3f3f;
const int MAXN=1e7+5;
inline ll read(){
      char ch=getchar();ll x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
int prime[MAXN],cnt=0,f[MAXN],T,mu[MAXN];
bool vis[MAXN];
namespace solution{
      void make_mu(){
            memset(vis,0,sizeof(vis));
            memset(f,0,sizeof(f));
            mu[1]=1;
            up(i,2,10000000){
                  if(!vis[i]){prime[++cnt]=i;mu[i]=-1;}
                  up(j,1,cnt){
                        if(prime[j]*i>10000000)break;
                        vis[prime[j]*i]=1;
                        if(i%prime[j]!=0)mu[i*prime[j]]=-mu[i];
                        else{
                              mu[i*prime[j]]=0;
                              break;
                        }
                  }
            }
            up(i,1,cnt)up(j,1,10000000){
                  if(prime[i]*j>10000000)break;
                  f[prime[i]*j]+=mu[j];
            }
            up(i,1,10000000)f[i]+=f[i-1];
      }
      void slove(ll a,ll b){
            ll ans=0,pos;
            if(a>b)swap(a,b);
            up(i,1,a){
                  pos=min(a/(a/i),b/(b/i));
                  ans+=(f[pos]-f[i-1])*(a/i)*(b/i);
                  i=pos;
            }
            cout<<ans<<endl;
      }
}
int main(){
      //freopen("input.in","r",stdin);
      freopen(FILE".in","r",stdin);
      freopen(FILE".out","w",stdout);
      using namespace solution;
      make_mu();
      T=read();
      while(T--){
            ll a=read(),b=read();
            slove(a,b);
      }
      return 0;
}

BZOJ 4407于神之怒

这些题为什么越来越难了QAQ

给下N,M,K.求

下面给出公式的推导:

//BZOJ 4407
//by Cydiater
//2016.7.27
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <map>
#include <iomanip>
#include <cmath>
#include <ctime>
using namespace std;
#define ll long long
#define up(i,j,n)       for(int i=j;i<=n;i++)
#define down(i,j,n)     for(int i=j;i>=n;i--)
const int MAXN=5e6+5;
const int LIM=5e6;
const int oo=0x3f3f3f3f;
const int mod=1e9+7;
inline int read(){
      char ch=getchar();int x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
ll f[MAXN],prime[MAXN],cnt=0,N,K,g[MAXN],T;
bool vis[MAXN];
namespace solution{
      inline ll quick_pow(ll a,ll b){
            ll tmp=1;
            while(b){
                  if(b&1)tmp=(tmp*a)%mod;
                  a=(a*a)%mod;
                  b>>=1;
            }
            return tmp;
      }
      void pret(){
            memset(vis,0,sizeof(vis));
            f[1]=1;
            up(i,2,LIM){
                  if(!vis[i]){prime[++cnt]=i;g[cnt]=quick_pow(i,K);f[i]=g[cnt]-1;}
                  up(j,1,cnt){
                        if(i*prime[j]>LIM)break;
                        vis[i*prime[j]]=1;
                        if(i%prime[j]!=0){
                              f[i*prime[j]]=(f[i]*f[prime[j]])%mod;
                        }else{
                              f[i*prime[j]]=(f[i]*g[j])%mod;
                              break;
                        }
                  }
            }
            up(i,1,LIM)f[i]=(f[i-1]+f[i])%mod;
      }
      void slove(ll a,ll b){
            ll ans=0,pos;
            if(a>b)swap(a,b);
            up(i,1,a){
                  pos=min(a/(a/i),b/(b/i));
                  ans+=(((f[pos]+mod-f[i-1])*(a/i))%mod)*(b/i);
                  ans%=mod;
                  i=pos;
            }
            printf("%lld\n",ans);
      }
}
int main(){
      freopen("input.in","r",stdin);
      using namespace solution;
      T=read();K=read();
      pret();
      while(T--)slove(read(),read());
      return 0;
}

BZOJ 2154

数论好坑啊

做这道题是为了做下一道题,这道题是下一道题的弱化版..但是我调试了几乎一个上午。

给定N,M求N,M内的lcm累加和。

下面是公式时间:


 然后双重分块就好了

这个调试的真恶心...

//BZOJ 2154
//by Cydiater
//2016.7.27
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define ll long long
#define up(i,j,n)       for(ll i=j;i<=n;i++)
#define down(i,j,n)     for(ll i=j;i>=n;i--)
const ll MAXN=1e7+5;
const ll LIM=1e7;
const ll mod=20101009;
const ll oo=0x3f3f3f3f;
inline ll read(){
      char ch=getchar();ll x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
ll prime[MAXN],cnt=0,mu[MAXN],N,M;
bool vis[MAXN];
namespace solution{
      void pret(){
            memset(vis,0,sizeof(vis));
            memset(mu,0,sizeof(mu));
            mu[1]=1;
            up(i,2,N){
                  if(!vis[i]){prime[++cnt]=i;mu[i]=-1;}
                  up(j,1,cnt){
                        if(prime[j]*i>N)break;
                        vis[prime[j]*i]=1;
                        if(i%prime[j]!=0){
                              mu[i*prime[j]]=-mu[i];
                        }else{
                              mu[i*prime[j]]=0;
                              break;
                        }
                  }
            }
            up(i,1,N)mu[i]=(mu[i-1]+(mu[i]*i*i)%mod)%mod;
      }
      ll sum(ll a,ll b){
            return ((a+1)*a/2%mod)*(b*(b+1)/2%mod)%mod;
      }
      ll F(ll a,ll b){
            ll pos,ans=0;
            if(a>b)swap(a,b);
            up(i,1,a){
                  pos=min(a/(a/i),b/(b/i));
                  ans=(ans+(mu[pos]-mu[i-1])*sum(a/i,b/i))%mod;
                  i=pos;
            }
            return ans;
      }
      void slove(ll a,ll b){
            if(a>b)swap(a,b);
            ll pos,ans=0;
            up(i,1,a){
                  pos=min(a/(a/i),b/(b/i));
                  ans=(ans+(i+pos)*(pos-i+1)/2%mod*F(a/i,b/i)%mod)%mod;
                  i=pos;
            }
            printf("%lld\n",(ans+mod)%mod);
      }
}
int main(){
      freopen("input.in","r",stdin);
      using namespace solution;
      N=read();M=read();
      if(N>M)swap(N,M);
      pret();
      slove(N,M);
      //cout<<"Time has passed:"<<1.0*clock()/1000<<"s!"<<endl;
      return 0;
}

BZOJ 2693:

这些数论题套路很多啊..

接着上一个公式:

//BZOJ 2693
//by Cydiater
//2016.7.29
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <queue>
#include <map>
#include <cstdlib>
#include <iomanip>
using namespace std;
#define ll long long
#define up(i,j,n)       for(ll i=j;i<=n;i++)
#define down(i,j,n)     for(ll i=j;i>=n;i--)
const int MAXN=1e7+10;
const int LIM=1e7;
const int mod=1e8+9;
const int oo=0x3f3f3f3f;
inline ll read(){
      char ch=getchar();ll x=0,f=1;
      while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
      while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
      return x*f;
}
ll f[MAXN],prime[MAXN],cnt=0,T;
bool vis[MAXN];
namespace solution{
      void pret(){
            memset(vis,0,sizeof(vis));
            f[1]=1;
            up(i,2,LIM){
                  if(!vis[i]){prime[++cnt]=i;f[i]=(i-i*i%mod)%mod;}
                  up(j,1,cnt){
                        if(prime[j]*i>LIM)break;
                        vis[prime[j]*i]=1;
                        if(i%prime[j]==0){
                              f[i*prime[j]]=(f[i]*prime[j])%mod;
                              break;
                        }
                        f[i*prime[j]]=(f[prime[j]]*f[i])%mod;
                  }
            }
            up(i,1,LIM)f[i]=(f[i]+f[i-1])%mod;
      }
      ll sum(ll a,ll b){
            ll tmp1=(a*(a+1)/2)%mod;
            ll tmp2=(b*(b+1)/2)%mod;
            return (tmp1*tmp2)%mod;
      }
      void slove(ll a,ll b){
            if(a>b)swap(a,b);
            ll pos,ans=0;
            up(i,1,a){
                  pos=min(a/(a/i),b/(b/i));
                  ans=(ans+(f[pos]-f[i-1])*sum(a/i,b/i)%mod)%mod;
                  i=pos;
            }
            printf("%lld\n",(ans+mod)%mod);
      }
}
int main(){
      //freopen("input.in","r",stdin);
      using namespace solution;
      T=read();
      pret();
      while(T--)slove(read(),read());
      return 0;
}
时间: 2024-12-24 08:07:23

Mobius 反演的相关文章

关于Mobius反演

欧拉函数 \(\varphi\) \(\varphi(n)=\)表示不超过 \(n\) 且与 \(n\) 互质的正整数的个数 \[\varphi(n)=n\cdot \prod_{i=1}^{s}(1-\frac{1}{p_i})\] 其中 \(n = {p_1}^{\alpha1} \cdot {p_2}^{\alpha2} \cdots {p_s}^{\alpha s} \cdot\) 是 \(n\) 的标准分解. 由此易见 \(\text{Euler}\) 函数是积性函数. 线性求 \(\

bzoj 2301: [HAOI2011]Problem b mobius反演 RE

http://www.lydsy.com/JudgeOnline/problem.php?id=2301 设f(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) = i的个数. 设F(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) % i == 0的个数,很简单的公式就是floor(n / i) * floor(m / i) 可知gcd(x, y) = k * i也属于F(i)的范围,所以可以反演得到f(i)的表达式. 算一次复杂度O(n),而且询问区间的时候要

【莫比乌斯反演】关于Mobius反演与lcm的一些关系与问题简化(BZOJ 2154 crash的数字表格&amp;&amp;BZOJ 2693 jzptab)

BZOJ 2154 crash的数字表格 Description 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数.例如,LCM(6, 8) = 24.回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张N*M的表格.每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j).一个4*5的表格如下: 1 2 3 4 5 2 2 6 4

Mobius反演的套路

T1 \(\sum_{i=1}^N \sum_{j=1}^M [(i,j)=1]\) \(f(d)=\sum_{i=1}^N \sum_{j=1}^M [(i,j)=d]\) \(g(d)=\sum_{i=1}^N \sum_{i=1}^M [d|(i,j)]=\lfloor \frac{N}{d} \rfloor \lfloor \frac{M}{d} \rfloor\) \(g(n)=\sum_{n|d} f(d)\) \(f(n)=\sum_{n|d} \mu(\frac{d}{n})g(

BZOJ 2440: [中山市选2011]完全平方数 二分答案 + 容斥原理 + 莫比乌斯反演

http://www.lydsy.com/JudgeOnline/problem.php?id=2440 第一道莫比乌斯反演的题目. 二分答案 + 容斥那里还是挺好想的. 二分一个答案val,需要[1, val]之间存在的合法数字个数 >= k即可. 怎么判断呢?可以容斥,开始的时候有ans = val个,但是这里明显有些数字不符合. ans -= ([1...val]中有多少个2^2倍  + [1...val]中有多少个3^2倍 + [1...val]中有多少个5^2倍) ...... 但是减

数论函数——莫比乌斯反演

一些函数的一些性质 取整函数 \(\lfloor x \rfloor\) (一)\(\lfloor x \rfloor <= x < \lfloor x \rfloor +1\) (二)对任意x与正整数a,b\(\lfloor \lfloor \frac{x}{a} \rfloor /b\rfloor=\lfloor \frac{x}{ab}\rfloor\) (三)对于正整数n,1 -- n中d的倍数个数为 \(\lfloor \frac{n}{d} \rfloor\) (四)若n为正整数,

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

基础不牢,地动山摇

这么多天过去了,即使自己步履蹒跚达到了一个短暂的小目标,但是自己的水平是怎样,自己比任何人都清楚. 我还是打算从头开始,按照知乎大神的步骤走上一次. 基本算法:1.枚举 1753 2965 2.贪心 1328 2109 2586 3.递归和分治法 4.递推 5.构造法 3295 6.模拟法 1068 1573 2993 2996 图算法: 1.图的深度优先遍历和广度优先遍历 2.最短路算法--多种 3.最小生成树算法 1789 2485 1258 3026 4.拓扑排序 1094 5.二分图最大

数字表格

mobius反演... ∏ni=1∏mj=1fi[gcd(i,j)] ∏nk=1fi[k]∑ni=1∑mj=1[gcd(i,j)=k] 设f(d)=∑ni=1∑mj=1[gcd(i,j)=k] ,表示最大公约数为k的数对数 F(d)=?nd???md? 表示公约数为k的数对数 根据莫比乌斯反演的公式f(d)=∑d|nμ(nd)?F(n) 所以式子可以变成 ∏k=1nfi[k]∑ni=1μ(i)??nk?i???mk?i? 但是实际上式子还能进一步的化简,设T=i?k ∏T=1n(∏d|nfi[d