BZOJ 2818 GCD 【欧拉函数 || 莫比乌斯反演】

传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2818

2818: Gcd

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 9236  Solved: 4126
[Submit][Status][Discuss]

Description

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.

Input

一个整数N

Output

如题

Sample Input

4

Sample Output

4

HINT


对于样例(2,2),(2,4),(3,3),(4,2)


1<=N<=10^7

解题思路:

老套路:GCD( x, y )  = p 转换成 GCD( x/p, y/p ) = 1;

那么按照原来的配方,我们需要枚举 x/p 或者 y/p 其中一个数,然后另外一个数的总数通过欧拉函数求得。

假设选择枚举 y/p ,那么还需要暴力一遍枚举素数。(一开始就是直接暴力。。。)

然而O( n ) 内可以同时筛出素数和欧拉函数值:https://oi.abcdabcd987.com/sieve-prime-in-linear-time/

同时记录一下欧拉函数前缀和 sum[k] ,根据上面的转换我们可知:

如果给出 x <= y ,则直接枚举素数枚举y,然后欧拉函数求所有方案数即可;

但是这里没有明确表明 x 和 y 的大小关系, 但是我们还是只求一半 即 (默认 x <= y)的情况,然后这个答案乘以 2 就是 (y <= x)的情况了,需要去一下重(即 x = y = 1)的情况。 

枚举 素数 p ,求 [ 1,  N/p ] 中互质的数对的总数, 即 2*sum[ N/p ]  - 1;

AC code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 const int MAXN = 1e7+10;
 5 bool com[MAXN];
 6 int primes, prime[MAXN], phi[MAXN];
 7 LL sum[MAXN];
 8 
 9 void get_phi(int n){
10     phi[1] = 1;
11     for (int i = 2; i <= n; ++i)
12     {
13       if (!com[i])
14       {
15         prime[primes++] = i;
16         phi[i] = i-1;
17       }
18       for (int j = 0; j < primes && i*prime[j] <= n; ++j)
19       {
20         com[i*prime[j]] = true;
21         if (i % prime[j])
22           phi[i*prime[j]] = phi[i]*(prime[j]-1);
23         else
24           { phi[i*prime[j]] = phi[i]*prime[j]; break; }
25       }
26       //sum[i] = sum[i-1]+phi[i];
27     }
28 }
29 int main()
30 {
31     int N;
32     scanf("%d", &N);
33     get_phi(N);
34     sum[1] = 1;
35     for(int i = 2; i <= N/2; i++){
36         sum[i] = sum[i-1]+phi[i];
37 //        phi[i] = phi[i-1]+phi[i];
38     }
39 //    printf("%d
", phi[1]);
40     LL ans = 0;
41     for(int i = 0; i < primes; i++){
42         ans = ans + (sum[N/prime[i]]*2-1);
43     }
44     printf("%lld
", ans);
45 
46     return 0;
47 }
原文地址:https://www.cnblogs.com/ymzjj/p/10357199.html