Diff-prime Pairs(思维+素数筛)

题目链接: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 
#include 
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 
#include 
#include 
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;
}

你可能感兴趣的:(题解,算法,素数筛)