这里主要提供这类题莫比乌斯的推导套路,推完柿子再维护东西思路会清晰许多
A hdu4135
题意:
给A B N 问【A,B】中与N互质的个数,N<=1e9,B<=1e15
公式推导:
先将题意化成柿子:
由 ,*指狄利克雷卷积,其实就是莫比乌斯反演啦
令,*是乘法,换元,并改变求和顺序
维护思路:
由于mu的特性,只有d是不同质因子的乘积对答案才有贡献
比如 2 2*5 2*7*11有贡献,2*2,12无贡献
贡献因子的定义:定义这种不同质因子乘积叫贡献因子
贡献因子的求法:预处理N的质因子,然后容斥N的质因子
求出ans:遍历N的所有贡献因子d
g++ ACcode 这里mu其实不用预处理
#include<bits/stdc++.h> #define ll long long using namespace std; bool isp[48005];int pri[48005];int mu[48005]; int p=0; void init(int n) { for(int i=1;i<=n;i++)isp[i]=1;mu[1]=1; for(int i=2;i<=n;i++) { if(isp[i]==1) pri[++p]=i,mu[i]=-1; for(int j=1;j<=p&&pri[j]*i<=n;j++) { isp[pri[j]*i]=0; if(i%pri[j]==0){mu[i*pri[j]]=0;break;} else mu[i*pri[j]]=-mu[i]; } } } vector<int>fac; void gfac(int n) { for(int i=1;pri[i]<=n/pri[i];i++) { if(n%pri[i]==0)fac.push_back(pri[i]); while(n%pri[i]==0)n/=pri[i]; } if(n>1)fac.push_back(n); } ll gans(ll B) { int up=fac.size(); ll ans=B; for(int i=1;i<(1<<up);i++) { int cnt=0;int mul=1; for(int j=0;j<up;j++) { if(((1<<j)&i)!=0) cnt++,mul*=fac[j]; } if(cnt&1)ans-=(B/mul); else ans+=(B/mul); } return ans; } int main() { init(45000);//cout<<45000*45000; int T;scanf("%d",&T);int kase=0; while(T--) { fac.clear(); ll A,B;int n;scanf("%lld %lld %d",&A,&B,&n); gfac(n); printf("Case #%d: ",++kase); printf("%lld\n",gans(B)-gans(A-1)); } }
好了,我们刚热完身,现在来一题难一点的
B.hdu5072 莫比乌斯反演+同色三角形套路
题意:
求n个不同的数(ai<=1e5,n<=1e5)中有多少组三元组(a, b, c)两两不互质或者两两互质
思路:
首先将题意转换一下,我们考虑平面上有N个点,两两不共线
一个三元组代表一个三角形ABC
由题意,AB,AC,BC 必然有(A,B)=(A,C)=(B,C)=1或!=1
那么相当于问有多少个同色三角形,AB互质将AB染成红色,不互质染成黑色
同色三角形的求法:C(n,3) - sum 从1到n:(该点与其他x个点互质*该点与其他y个点不互质)
现在问题的核心在:对于ai,有多少个aj与ai互质?
转换成柿子:
柿子推导:
维护方法:
统计有多少个ai含有贡献因子d即可
A线性筛预处理1e5以内的mu,
B利用这个mu用通用筛维护出1e5以内每个数的贡献因子
C对每个ai暴力遍历贡献因子,维护出num
D计算答案
g++ 312ms
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e5+5; bool isp[maxn];int pri[maxn];int mu[maxn]; int num[maxn];int p=0; vector<int>E[maxn];int a[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void init() { int up=100001;//A线性筛 for(int i=1;i<=up;i++)isp[i]=1;mu[1]=1; for(int i=2;i<=up;i++) { if(isp[i]==1)mu[i]=-1,pri[++p]=i; for(int j=1;j<=p&&pri[j]*i<=up;j++) { isp[pri[j]*i]=0; if(i%pri[j]==0){mu[i*pri[j]]=0;break;} else mu[i*pri[j]]=-mu[i]; } } for(int i=1;i<=up;i++)//B预处理每个数的mu贡献因子 { if(mu[i]) for(int j=i;j<=up;j+=i) E[j].push_back(i); } } int main() { init();int T;scanf("%d",&T); while(T--) { ll n;scanf("%lld",&n);memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) { a[i]=read();//scanf("%d",&a[i]); for(int j=0;j<E[a[i]].size();j++) num[E[a[i]][j]]++;//C }ll ans=0; for(int i=1;i<=n;i++)//D { int tem=0;if(a[i]==1)continue; for(int j=0;j<E[a[i]].size();j++) tem+=mu[E[a[i]][j]]*num[E[a[i]][j]]; ans+=tem*(n-1-tem); } printf("%lld\n",n*(n-1)*(n-2)/6-ans/2);//同色三角形套路 } }