系列 莫比乌斯反演
Posted yyc-jack-0920
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了系列 莫比乌斯反演相关的知识,希望对你有一定的参考价值。
几个有用的结论:
记 $(f*g)(n)=sumlimits_{d|n} f(d) * g(frac{n}{d})$
则有$mu * 1 = [n=1]$与$phi *1 = id$
若$F(n)=sumlimits_{d|n} f(d)$
则$f(n)=sumlimits_{d|n} mu(d) * F(frac{n}{d})$
bzoj 2190 仪仗队
题目大意:
求$n*n$的矩形中能从左下角被直接看到的点的个数
思路:
设左下角$(0,0)$ 则相当于求$sumlimits_{i=1}^{n-1} sumlimits_{j=1}^{n-1} [gcd(i,j)==1]+2$($(1,0),(0,1)$
将式子转化为$1+ 2* sumlimits_{i=1}^{n-1} sumlimits_{j=1}^{i} [gcd(i,j)==1] $(由于有$(1,0),(0,1),(1,1)$三个特殊点存在
然后发现满足欧拉函数的定义,则所求为$1+2* sumlimits_{i=1}^{n-1} phi(i) $ 筛出欧拉函数即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 50010 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 28 return x*f; 29 } 30 int n,tot,p[MAXN+100],ntp[MAXN+100],phi[MAXN+100]; 31 void mem() 32 { 33 phi[1]=1; 34 rep(i,2,MAXN) 35 { 36 if(!ntp[i]) p[++tot]=i,phi[i]=i-1; 37 rep(j,1,tot) if(i*p[j]>MAXN) break; 38 else {ntp[i*p[j]]=1;if(i%p[j]) phi[i*p[j]]=phi[i]*phi[p[j]];else {phi[i*p[j]]=phi[i]*p[j];break;}} 39 } 40 rep(i,2,n-1) phi[i]+=phi[i-1]; 41 } 42 int main() 43 { 44 n=read();mem();printf("%d ",n>1?phi[n-1]<<1|1:0); 45 }
bzoj 2818 Gcd
题目大意:
求有序数对$(i,j),i,j leq n$满足$gcd(i,j)$为素数的数对个数
思路:
法1:和上一题很相似,设$p$为素数则$sumlimits_{i=1}^n sumlimits_{j=1}^n [gcd(i,j)==p] =sumlimits_{i=1}^{n/p} sumlimits_{j=1}^{n/p} [gcd(i,j)==1]$
这样我们枚举每一个素数就可以解决了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 10001000 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 28 return x*f; 29 } 30 int n,tot,p[MAXN],ntp[MAXN+5],phi[MAXN]; 31 ll ans,sum[MAXN]; 32 void mem() 33 { 34 phi[1]=1; 35 rep(i,2,n) 36 { 37 if(!ntp[i]) p[++tot]=i,phi[i]=i-1; 38 rep(j,1,tot) if(i*p[j]>n) break; 39 else {ntp[i*p[j]]=1;if(i%p[j]) phi[i*p[j]]=phi[i]*phi[p[j]];else {phi[i*p[j]]=phi[i]*p[j];break;}} 40 } 41 rep(i,1,n) sum[i]=sum[i-1]+phi[i]; 42 } 43 int main() 44 { 45 n=read();mem(); 46 rep(i,1,tot) ans+=sum[n/p[i]]*2-1;printf("%lld ",ans); 47 }
法2:因为$gcd(i,j)==1$的形式可以转化为$sumlimits_{d|gcd(i,j)} mu(d)$
由于对于每一个$d$,相对应的$i,j$有$n/i,n/j$个。所以前两个枚举是没有必要的,设$m$为$n/p$,式子为$sumlimits_{d=1}^m mu(d)*frac{m}{d}*frac{m}{d}$
枚举素数后数论分块
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 10001000 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 28 return x*f; 29 } 30 int n,tot,p[MAXN],ntp[MAXN+5],mu[MAXN]; 31 ll ans,sum[MAXN]; 32 void mem() 33 { 34 mu[1]=1; 35 rep(i,2,n) 36 { 37 if(!ntp[i]) p[++tot]=i,mu[i]=-1; 38 rep(j,1,tot) if(i*p[j]>n) break; 39 else {ntp[i*p[j]]=1;if(i%p[j]) mu[i*p[j]]=-mu[i];else {mu[i*p[j]]=0;break;}} 40 } 41 rep(i,1,n) sum[i]=sum[i-1]+mu[i]; 42 } 43 ll solve(int x,ll res=0) 44 { 45 int pos,lmt=n/x;rep(i,1,lmt) {pos=lmt/(lmt/i);res+=1LL*(sum[pos]-sum[i-1])*(lmt/i)*(lmt/i);i=pos;} 46 return res; 47 } 48 int main() 49 { 50 n=read();mem(); 51 rep(i,1,tot) ans+=solve(p[i]);printf("%lld ",ans); 52 }
bzoj 1101 Zap
题目大意:
求有序数对$(i,j),ileq a,j leq b$满足$gcd(i,j)==d$的数对个数
思路:
和上一题基本一样
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 60100 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 28 return x*f; 29 } 30 int n,tot,p[MAXN],ntp[MAXN+5],mu[MAXN]; 31 ll ans,sum[MAXN]; 32 void mem(int n) 33 { 34 mu[1]=1; 35 rep(i,2,n) 36 { 37 if(!ntp[i]) p[++tot]=i,mu[i]=-1; 38 rep(j,1,tot) if(i*p[j]>n) break; 39 else {ntp[i*p[j]]=1;if(i%p[j]) mu[i*p[j]]=-mu[i];else {mu[i*p[j]]=0;break;}} 40 } 41 rep(i,1,n) sum[i]=sum[i-1]+mu[i]; 42 } 43 ll solve(int x,int y,ll res=0) 44 { 45 int pos,lmt=min(x,y);rep(i,1,lmt) 46 {pos=min(x/(x/i),(y/(y/i)));res+=1LL*(sum[pos]-sum[i-1])*(x/i)*(y/i);i=pos;} 47 return res; 48 } 49 int main() 50 { 51 int T=read(),a,b,d;mem(50010);while(T--) 52 {a=read(),b=read(),d=read();printf("%lld ",solve(a/d,b/d));} 53 }
bzoj 4804 欧拉心算
题目大意:
求$sumlimits_i^n sumlimits_i^n phi(gcd(i,j))$
思路:
枚举$gcd$ 得到$sumlimits_{k=1}^n phi(k) sumlimits_{i=1}^n sumlimits_{j=1}^n [gcd(i,j)==1]$
后面的式子转化为第一题的样子即原式为$sumlimits_{k=1}^n phi(k) (-1+2*sumlimits_{i=1}^{n/k}phi(i))$
设$f(k)=-1+2*sumlimits_{i=1}^k phi(i)$ 则原式为$sumlimits_{k=1}^n phi(k)*f(frac{n}{k})$
使用数论分块即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 10000001 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 28 return x*f; 29 } 30 int n,tot,p[MAXN],ntp[MAXN]; 31 ll ans,phi[MAXN],f[MAXN]; 32 void mem(int n) 33 { 34 phi[1]=1; 35 rep(i,2,n) 36 { 37 if(!ntp[i]) p[++tot]=i,phi[i]=i-1; 38 rep(j,1,tot) if(i*p[j]>n) break; 39 else {ntp[i*p[j]]=1;if(i%p[j]) phi[i*p[j]]=phi[i]*phi[p[j]];else {phi[i*p[j]]=phi[i]*p[j];break;}} 40 } 41 rep(i,1,n) phi[i]+=phi[i-1],f[i]=-1+(phi[i]<<1); 42 } 43 ll solve(int n,ll res=0) 44 { 45 int pos;rep(i,1,n) {pos=n/(n/i);res+=1LL*(phi[pos]-phi[i-1])*f[n/i];i=pos;}return res; 46 } 47 int main() 48 { 49 int T=read(),a,b,d;mem(10000000);while(T--) 50 {a=read();printf("%lld ",solve(a));} 51 }
(卡我一个数组的空间常数怕不是有毒
以上是关于系列 莫比乌斯反演的主要内容,如果未能解决你的问题,请参考以下文章