传送门:洛谷2568
题目描述
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.
分析
题目所求为gcd(x, y) = p(p表示质数)的个数;对此,可以转化成:gcd(x/p, y/p) = 1;于是可以考虑欧拉函数,然后乱搞一下:
对于
ϕ
ϕ
(x) 所属的数对(x, y), 它可以衍生出 若干组(这里的组是指 (x, y), (y, x)),满足条件的数对 (x * p , y * p) {易知,每组所产生的数对是不同的}
令k表示与i相乘后不大于n的质数个数, cnt表示n以内的质数个数
则: ans = cnt +
∑ni=2
∑
i
=
2
n
ki
∗
∗
∗
∗
2
{由于未计算 (p, p) 的情况,所以加上cnt, 由于有(x, y)与(y,x) 两种,所以乘2}
PS: 为欧拉函数,表示在
[
[
1 x
)
)
中与x互质的个数
举个例子: n = 10, ans = 30
10以内的质数为2,3,5,7
故 ans=4(质数个数)+6+8+4+8=30; a n s = 4 ( 质 数 个 数 ) + 6 + 8 + 4 + 8 = 30 ;
ps:由上也可以推测k是递减的
顺便讲讲欧拉函数的线筛求法(具体见代码):
主要利用三个性质:
若x为质数,则
ϕ(x)=x−1
ϕ
(
x
)
=
x
−
1
若
p∣x
p
∣
x
且
p2∣x
p
2
∣
x
,则
ϕ(x)=ϕ(x/p)∗p
ϕ
(
x
)
=
ϕ
(
x
/
p
)
∗
p
若
p∣x
p
∣
x
且
p2∤x
p
2
∤
x
,则
ϕ(x)=ϕ(x/p)∗(p−1)
ϕ
(
x
)
=
ϕ
(
x
/
p
)
∗
(
p
−
1
)
代码
注意开long long
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define IL inline
using namespace std;
IL int read()
{
int sum = 0;
bool k = 1;
char c = getchar();
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = 0;
for(;'0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + c - '0';
return k ? sum : -sum;
}
bool is_prime[10000005];
int cnt;
int prime[664600];
int phi[10000005];
IL void get_prime(int n)
{
is_prime[1] = 1;
phi[1] = 1;
for(int i = 2, j; i <= n; ++i)
{
if(!is_prime[i]) { prime[++cnt] = i; phi[i] = i - 1;}
for(j = 1; j <= cnt && (long long)i * prime[j] <= n; ++j)
{
is_prime[i * prime[j]] = 1;
phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
if(!(i % prime[j])) break;
}
}
}
int main()
{
int n = read();
get_prime(n);
long long ans = cnt;
int r = cnt;
for(int i = 2; i <= n; ++i)
{
for(;r && i * prime[r] > n; --r);
if(!r) break;
ans += phi[i] * r << 1;
}
printf("%lld", ans);
return 0;
}