题目链接:bzoj2818
题目大意:
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.
题解:
欧拉函数或莫比乌斯反演
设d∈[1,n]是一个质数。
原式即
∑i=1n∑j=1n∑gcd(i,j)=d1
套路一下:
∑i=1n∑j=1n∑d∑gcd(id,jd)=11
额第三个求和是在枚举范围内的质数。
欧拉函数的做法就是化成:
∑d∑i=1n∑j=1n[gcd(id,jd)=1]
然后看式子的后半部分,就是在求[1,n]中的与 id 互质的数的个数,就是 ϕ(i) 。所以可以预处理欧拉函数及其前缀和,枚举质数 d 然后直接累加就好了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define maxn 10001000
#define N 701000
bool ispri[maxn];LL sum[maxn];
int n,cnt,phi[maxn],pri[N];
void Eular(int lim)
{
cnt=0;phi[1]=1;
for (int i=2;i<=lim;i++)
{
if (!ispri[i]) {pri[++cnt]=i;phi[i]=i-1;}
for (int j=1;j<=cnt && pri[j]*i<=lim;j++)
{
ispri[i*pri[j]]=true;
if (i%pri[j]==0)
{
phi[i*pri[j]]=pri[j]*phi[i];
// mu[i*pri[j]]=0;
break;
}
phi[i*pri[j]]=(pri[j]-1)*phi[i];
// mu[i*pri[j]]=-mu[i];
}
}sum[0]=0;
for (int i=1;i<=lim;i++) sum[i]=sum[i-1]+phi[i];
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int n,i;LL ans=0;
scanf("%d",&n);
Eular(n);
for (i=1;i<=cnt;i++)
{
int lim=n/pri[i];
ans+=sum[lim]*2-1;
}
printf("%lld\n",ans);
return 0;
}
莫比乌斯反演的做法我现在还不是很懂怎么化出来..先挖个坑
来填坑
莫比乌斯反演的做法则是化成:
把 id 、 jd 什么的换成 i 、
反演一下:
∑d∑i=1nd∑j=1nd∑t|i,t|jμ(t)
即
∑d∑t=1n∑i=1,t|ind∑j=1,j|tndμ(t)
实际上后半部分就是在求有多少对 i ,
所以式子就是:
∑d∑t=1nndt×ndt×μ(t)
预处理 mobius 函数及其前缀和,枚举质数 d ,然后后面的
懒得再打了。。
看这位 dalao的吧,谢谢dalao的解疑。