传送门
题目描述
给定整数N,求1<=x,y<=N(N<=10^7)且Gcd(x,y)为素数的
数对(x,y)有多少对.
输入
一个整数N
输出
如题
样例输入
4
样例输出
4
解题思路:
这个题目出来可以用欧拉函数来解答之外,点击此处 这是欧拉函数解这道题的思路
那么我们还可以用莫比乌斯反演来做,首先介绍一下莫比乌斯反演的公式:
F(n)=∑d|nf(d) ⇒f(n)=∑d|nF(nd)miu(d)−−−(1)
其实还可以这么写:
F(n)=∑n|df(d) ⇒f(n)=∑n|dmiu(dn)F(d)−−−(2)
在这道题里面就可以这么设了,那么我们现在可以给两个f函数赋值了:
f(d):是满足GCD(x,y)==d的(1<=x,y<=n)的对数
F(d):是满足d|GCD(x,y)的函数(1<=x,y<=n)的对数
那么我们可以写出
F(d)=nd∗nd−−−(3)
所以根据式子(2)和(3)可以知道
f(n)=∑n|dmiu(dn)nd∗nd
又因为 GCD(x,y) 是素数,那么我们可以枚举区间[1,n]的每个素数(素因子分解可以实现)
ans=∑pn(∑dnmiu(d)np∗d∗np∗d)(在这里p是素数)
然后再YY一下就可以搞定了。。。
上代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int MAXN = 1e7+5;
bool prime[MAXN];
int p[MAXN];
int mu[MAXN];
int phi[MAXN];
int k;
///mu函数
void Init()
{
k = 0;
memset(prime, 0, sizeof(prime));
mu[1] = 1;
for(int i=2; i<MAXN; i++)
{
if(!prime[i])
{
p[k++] = i;
mu[i] = -1;
phi[i] = 1;
}
for(int j=0; j<k&&i*p[j]<MAXN; j++)
{
prime[i*p[j]] = 1;
if(i%p[j] == 0)
{
mu[i*p[j]] = 0;
phi[i*p[j]] = mu[i];//p[j] * phi[i];
break;
}
else
{
mu[i*p[j]] = -mu[i];
//phi[i*p[j]] = (p[j]-1) * phi[i];
phi[i*p[j]] = mu[i] - phi[i];
}
}
}
}
int sum[MAXN];
void get_sum()
{
sum[0] = 0;
for(int i=1; i<MAXN; i++)
sum[i] = sum[i-1]+phi[i];
}
int main()
{
Init();
get_sum();
LL n;
scanf("%lld",&n);
LL ans = 0;
for(int i=1,last; i<=n; i=last+1)
{
last = n/(n/i);
ans += (n/i)*(n/i)*(sum[last]-sum[i-1]);
}
printf("%lld\n",ans);
return 0;
}