这里主要提供这类题莫比乌斯的推导套路,推完柿子再维护东西思路会清晰许多
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);//同色三角形套路
}
}
C 17ICPC乌鲁木齐现场赛 K题 :
https://blog.csdn.net/animalcoder/article/details/79438720