Gcd
题目链接
题目大意
给你一个数n, 1<=x,y<=n 现在让你求gcd(x,y)=p,p为质数的x,y共有多少对。
题解
莫比乌斯反演
看了很多资料,对的错的都看了不少…..总算有了一些头绪。
首先莫比乌斯反演有两种形式,一般的,我们用
F(x)=∑d|xf(d) → f(x)=∑d|xμ(d)F(xd)
还有一种形式
F(x)=∑x|df(d) → f(x)=∑x|dμ(dx)F(d)
在这里我们用第二种形式:
设f(d)为gcd(x,y)=d的符合条件的(x,y)的对数设F(d)为d|gcd(x,y)的符合条件的(x,y)的对数
根据反演,有
f(x)=∑x|dμ(dx)F(d)
根据F(x)的定义 F(x)=(Nd)2
所以我们有
f(x)=∑x|dμ(dx)∗(Nd)2
到这里,我们可以写出最终的结果:
ans=∑x是质数nf(x)=∑x是质数∑x|dμ(dx)∗(Nd)2
为了简化计算,我们考虑先枚举d,再枚举x:
ans=∑d=2n(Nd)2∑x|d且x是质数μ(dx)
直接枚举时间肯定不够,不过可以看到我们只要求出后面的一项 ∑x|d且x是质数μ(dx) 我们就可以在线性时间内求出ans了。所以在这里,我们设:
g(x)=∑p|xμ(xp) (p是质数)
对于g(x),我们看到 g(x) 和 μ(x) 有关,可以想到是否可以在筛出 μ(x) 的时候同时筛出g(x)。在这里我们分类讨论:
g(i∗prime(j))=∑p|i∗prime(j)μ(i∗prime(j)p)
首先,如果 prime(j)|i :
说明i的因子中有prime(j),所以除了prime(j)与p相同的情况其值等于μ(i),其他的情况g(i∗prime(j))=0
所以有g(i∗prime(j))=μ(i) ( prime(j)|i )(*)
如果prime(j)不能整除i的话:
首先考虑 prime(j)!=p :
g(i∗prime(j))=∑p|i∗prime(j)μ(ip)∗μ( prime(j) )
因为这里我们是在枚举p算和,所以 μ( prime(j) ) 可以提前,得到
g(i∗prime(j))=μ( prime(j) )∑p|i∗prime(j)μ(ip)
可以看到 μ( prime(j) ) 为-1,而后面就是 g(i) 所以最终求和,所以此时
g(i∗prime(j))=−g(i)
而如果 prime(j)=p 的话,消掉又变成 μ(i) 了,所以在prime(j)不能整除i的情况下:
g(i∗prime(j))=μ(i)−g(i)(**)
综上所述
g(i∗prime(j))={μ(i) prime(j)|iμ(i)−g(i) prime(j)不能整除i
到这里,问题圆满解决,最后求出g(i)的前缀和然后分块求出最终结果就行了。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#define LL long long
#define maxn 10000005
using namespace std;
int n,p[maxn],g[maxn],mu[maxn],num;
bool vis[maxn];
void setup(int high)
{
memset(g,0,sizeof(g));
mu[1]=1; num=0;
for (int i=2;i<=high;i++)
{
if (!vis[i])
{
vis[i]=1; p[num++]=i;
mu[i]=-1;
g[i]=1;
}
for (int j=0;j<num && i*p[j]<=high;j++)
{
vis[i*p[j]]=1;
if (i%p[j])
{
mu[i*p[j]]=-mu[i];
g[i*p[j]]=mu[i]-g[i];
}
else
{
mu[i*p[j]]=0;
g[i*p[j]]=mu[i];
break;
}
}
}
for (int i=1;i<high;i++) g[i]+=g[i-1];
}
int main()
{
setup(maxn-5);
scanf("%d",&n);
int last=0;
LL ans=0;
for (int T=2;T<n;T=last+1)
{
last=(n/(n/T));
ans+=(LL) (g[last]-g[T-1])*(n/T)*(n/T);
}
printf("%lld\n",ans);
return 0;
}