题目链接
题目描述
Eddy tried to solve it with inclusion-exclusion method but failed. Please help Eddy to solve this problem.
Note that pair (i1, j1) and pair (i2, j2) are considered different if i1 ≠ i2 or j1 ≠ j2.
输入描述:
Input has only one line containing a positive integer N.
1 ≤ N ≤ 107
输出描述:
Output one line containing a non-negative integer indicating the number of diff-prime pairs (i,j) where i, j ≤ N
case 1
input:
3
output:
2
case 2
input:
5
output:
6
题目大意:求 1~N 内满足 i / gcd(i, j) , j / gcd(i, j) 的有序对 i,j 的个数。
思路:
官方题解:
Main Idea: Math, Prime Sieve, Prefix Sum
If gcd(i_1, j_1) is not equal to gcd(i_2, j_2), (i_1, j_1) won’t be equal to (i_2, j_2).
The answer will be sum of number of diff-prime pairs whose gcd is g for each g.
Iterate each g, and find two distinct prime p_1, p_2. Then, (g p_1, g p_2) will be an answer if g p_1 <= N and g p_2 <= N. It will be reduced to find the number of prime within (N/g). It can be done by prime sieve and prefix sum.
Since p_1 not equal to p_2, it’s obvious that gcd(g p_1, g p_2)=g
Overall Time complexity: O(N) Overall Space complexity: O(N)
一开始暴力i, j,结果也很暴力直接超时,剪枝也没办法,O(N^2)肯定不用想了
其实这道题的做法是暴力最大公因数 gcd(i, j), 而不是直接暴力i, j, 因为 (i_1, j_1) 和 (i_2, j_2) 不相同说明他们的公因数也不同。所以我们只需要枚举1~N内的公因数 g 再寻找公因数相同下在区间(2, N/g)素数对组合情况就可以了,可以预处理用埃氏筛法打素数表,至于素数对组合,根据排列组合 sum[N/g]*(sum[N/g]-1), sum为前缀和,可以线性预处理出来。所以整道题的算法都是线性的。
AC code:
///2018年牛客暑假多校训练赛第三场 H #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; const int MAXN = 1e7+10; bool is_prime[MAXN]; int num[MAXN]; int N; void sivev(int N) ///素数表 { int p = 0; for(int i = 0; i <= N; i++) is_prime[i] = true; is_prime[0] = is_prime[1] = 0; for(int i = 2; i <= N; i++) { if(is_prime[i]) { num[i] = 1; for(int j = 2*i; j <= N; j+=i) is_prime[j] = 0; } } } int main() { scanf("%d", &N); sivev(N); for(int i = 1; i <= N; i++) num[i]+=num[i-1]; long long int ans = 0; for(int g = 1; g <= N; g++) { ans+=num[N/g]*(num[N/g]-1); } printf("%lld ", ans); return 0; }