Diff-prime Pairs(思維+素數篩)

小小願望啦發表於2020-10-09

題目連結:https://ac.nowcoder.com/acm/contest/7865/J

題目描述
Eddy has solved lots of problem involving calculating the number of coprime pairs within some range. This problem can be solved with inclusion-exclusion method. Eddy has implemented it lots of times. Someday, when he encounters another coprime pairs problem, he comes up with diff-prime pairs problem. diff-prime pairs problem is that given N, you need to find the number of pairs (i, j), where i g c d ( i , j ) \frac{i}{gcd(i,j)} gcd(i,j)i and j g c d ( i , j ) \frac{j}{gcd(i,j)} gcd(i,j)j are both prime and i ,j ≤ N. gcd(i, j) is the greatest common divisor of i and j. Prime is an integer greater than 1 and has only 2 positive divisors.
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 ≤ 10 7 ^7 7
輸出描述
Output one line containing a non-negative integer indicating the number of diff-prime pairs (i,j) where i, j ≤ N
樣例1
輸入
3
輸出
2
樣例2
輸入
5
輸出
6

思路
方法一:暴力列舉 i i i j j j,會TLE

#include <iostream>
#include <cstdio>
using namespace std;
int n;
int gcd(int a, int b) {
	if (b == 0) return a;
	return gcd(b, a%b);
}
bool isPrime(int x) {
	if (x == 1) return false;//1不是素數 
	for (int i = 2; i * i <= x; i++) {
		if ((x % i) == 0) return false;
	}
	return true;
}
int main() {
	freopen("Diff-prime Pairs.in", "r", stdin);
	while (~scanf("%d", &n)) {
		int ans = 0;
		for (int i = 2; i <= n; i++) {
			for (int j = 2; j <= i; j++) {
				int g = gcd(i, j);
				if (isPrime(i/g) && isPrime(j/g)) {
					if (i == j) ans++;//i一定不可能等於j 
					else ans += 2;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0; 
} 

需要注意兩點:

  • 函式isPrime()需要單獨判斷1,1不是素數
  • 因為pair(i,j)和pair(j,i)是對稱的,所以每次找到一對ans+=2,但程式碼中i==j的情況不可能出現,因為如果i和j相等,gcd(i,j)=i=j,而1不是素數,不會進入if中

方法二:轉換思路,不直接找 i i i j j j,而是列舉 i i i j j j的最大公因數 g g g,所有滿足 i ∗ g < = n i*g<=n ig<=n j ∗ g < = n j*g<=n jg<=n的不相等的 i i i j j j就是我們要找的,我們通過素數篩把素數找到,然後用陣列sum[ ]記錄字首素數的個數

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e7+7;
int n;
int a[N], sum[N];
void init(int n) {
	memset(sum, 0, sizeof(0));
	a[0] = a[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (a[i] == 0) {
			sum[i] = 1;
			for (int j = 2*i; j <= n; j+=i) {
				a[j] = 1;
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		sum[i] += sum[i-1];
	}
}
int main() {
	freopen("Diff-prime Pairs.in", "r", stdin);
	while (~scanf("%d", &n)) {
		init(n);
		ll ans = 0;
		for (int g = 1; g <= n; g++) {
			ans += sum[n/g] * (sum[n/g]-1);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

相關文章