首先介绍一下莫比乌斯函数的形式
1. 当d=1d=1时,μ(d)=1 2. 当d=p1*p2*p3*…*pk且pi为互异素数时,μ(d)=(−1)^k。(说直白点,就是d分解质因数后,没有幂次大于平方的质因子,此时函数值根据分解的个数决定) 3. 只要当d含有任何质因子的幂次大于2,则函数值为0
在线性筛(欧拉筛法)的基础之上稍加修改就可以得到筛莫比乌斯函数的,函数
1 #include<cstdio> 2 const int maxn=105; 3 int cnt; 4 bool vis[maxn]; 5 int mu[maxn],prim[maxn]; 6 void get_mu(int n) 7 { 8 mu[1]=1; 9 for(int i=2;i<=n;i++) 10 { 11 if(!vis[i]) {prim[++cnt]=i;mu[i]=-1;} 12 for(int j=1;j<=cnt&&prim[j]*i<=n;j++) 13 { 14 vis[prim[j]*i]=1; 15 if(i%prim[j]==0) break; 16 else mu[i*prim[j]]=-mu[i]; 17 } 18 } 19 } 20 int main() 21 { 22 get_mu(100); 23 for(int i=1;i<=100;i++) 24 printf("%d ",mu[i]); 25 return 0; 26 }
还有其变式形式:
据说这种形式更加常用哦
BZOJ2301,它的题意是这样的,
对于给出的 n 个询问,每次求有多少个数对(x,y),满足 a≤x≤b, c≤y≤d,且 gcd(x,y) = k,
gcd(x,y)函数为 x 和 y 的最大公约数
设calc(n,m)表示在1<=x<=n,1<=y<=m,满足gcd(x,y)是k的(x,y)的对数
那么当限定区间在(a,b)和(c,d)的时候,可以根据容斥原理确定出来
calc(b,d)−calc(a−1,d)−calc(b,c−1)+calc(a−1,c−1)
那么对于求每一个calc(x,y)
首先要明确的是求gcd(x,y)=k就是求gcd(x/k,y/k)=1的解
然后设f(i)为gcd(x,y)=i时(x,y)的对数,F(i)表示满足i|gcd(x,y)的(x,y)的对数,显然F(i)=[n/i][m/i] 这里[]就是向下取整
F函数很容易求得,然后我们用莫比乌斯反演公式来求那个f函数就好了
然后在计算向下取整的时候,需要用到一个整除分块的东西提高效率
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=50005; 5 int tot; 6 bool mark[maxn]; 7 int sum[maxn],mu[maxn],pri[maxn]; 8 inline int read() 9 { 10 int x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 void getmu() 16 { 17 mu[1]=1; 18 for(int i=2;i<=50000;i++) 19 { 20 if(!mark[i]) {mu[i]=-1;pri[++tot]=i;} 21 for(int j=1;j<=tot&&i*pri[j]<=50000;j++) 22 { 23 mark[i*pri[j]]=1; 24 if(i%pri[j]==0) {mu[i*pri[j]]=0;break;} 25 else mu[i*pri[j]]=-mu[i]; 26 } 27 } 28 for(int i=1;i<=50000;i++) 29 sum[i]=sum[i-1]+mu[i]; 30 } 31 int cal(int n,int m) 32 { 33 if(n>m) swap(n,m); 34 int ans=0,pos; 35 for(int i=1;i<=n;i=pos+1) 36 { 37 pos=min(n/(n/i),m/(m/i)); 38 ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i); 39 } 40 return ans; 41 } 42 int main() 43 { 44 int T; 45 int a,b,c,d,k; 46 getmu(); 47 T=read(); 48 while(T--) 49 { 50 a=read();b=read();c=read();d=read();k=read(); 51 a--;c--; 52 a/=k;b/=k;c/=k;d/=k; 53 int ans=cal(a,c)+cal(b,d)-cal(a,d)-cal(b,c); 54 printf("%d ",ans); 55 } 56 return 0; 57 }