CodeForces-Another Problem About Dividing Numbers

题目

做法评论区都给的差不多了,其实时间上可以从原来的\(\mathcal{O(T\sqrt{n})}\),优化成\(\mathcal{\dfrac{O(T\sqrt{n})}{\ln\sqrt{n}}}\),感谢讨论区佬们的指点,蒟蒻只是起到了整理作用。

我们以 \(10^{12}\) 为例子,讲述线性筛的优势。

没有素数表:

  • 我们需要逐一检查从 \(2\)\(\sqrt{N}\) 的所有可能因数。
  • 这个情况下的时间复杂度是 \(O(\sqrt{N})\)
  1. 时间复杂度:\(O(\sqrt{N})\)
  2. 最大检查的质因数: \(\sqrt{10^{12}} = 10^6\)
  3. 检查次数: 大约是 \(10^6\)

有素数表:

  • 我们只需要检查素数表中的素数作为可能因数。
  • 根据素数定理,前 \(N\) 个自然数中大约有 \(\frac{N}{\ln N}\) 个素数。
  • 因为我们只需要检查到 \(\sqrt{N}\) 的素数,所以在范围 \([2, \sqrt{N}]\) 内的素数大约有 \(\frac{\sqrt{N}}{\ln \sqrt{N}}\) 个。
  • 使用对数的性质 \(\ln \sqrt{N} = \frac{1}{2} \ln N\),所以在范围 \([2, \sqrt{N}]\) 内的素数大约有 \(\frac{\sqrt{N}}{\frac{1}{2} \ln N} = \frac{2 \sqrt{N}}{\ln N}\) 个。
  1. 时间复杂度: \(O\left(\frac{2 \sqrt{N}}{\ln N}\right)\)

  2. 最大检查的质因数: \(\sqrt{10^{12}} = 10^6\)

  3. 在范围 ([2, 10^6]) 内的素数个数:

    \([ \frac{2 \cdot 10^6}{\ln 10^{12}} = \frac{2 \cdot 10^6}{12 \ln 10} \approx \frac{2 \cdot 10^6}{27.63} \approx 72381 ]\)


因此,有素数表的情况下,我们只需要大约进行 \(72381\) 次检查,而不是 \(1000000\) 次。这意味着时间复杂度从 \(O(10^6)\) 降低到了\(\mathcal{O(72381)}\),约优化了 \(14\) 倍。

CODE

#include <bits/stdc++.h>
using namespace std;
const int range = 5e5 + 10;
int n;
int a, b, k;
int step1 = 0;
int step2 = 0;
bool isprime[range];
int prime[range];
int cnt;
void euler() {
	isprime[1] = 1;
	for (int i = 2; i <= range; i++) {
		if (!isprime[i]) {
			prime[++cnt] = i;
		}
		for (int j = 1; j <= cnt && i * prime[j] <= range; j++) {
			isprime[i * prime[j]] = 1;
			if (i % prime[j] == 0)break;
		}
	}
}
int cal(int n) {
	int res = 0;
	for (int i = 1; i <= cnt; i++) {
		if (prime[i]*prime[i] > n)break;
		while (n % prime[i] == 0) {
			n /= prime[i];
			res++;
		}
	}
	if (n > 1)res++;
	return res;
}
void solve(int t) {

	cin >> a >> b >> k;
	step1 = 0;
	step2 = 0;
	if (a == b && k == 1) {
		cout << "NO" << endl;
		return ;
	}
	if (k == 1) {
		if (a < b)swap(a, b);
		if (a == 1 || b == 1) {
			cout << "YES" << endl;
			return;
		} else if (a % b == 0) {
			cout << "YES" << endl;
			return ;
		} else cout << "NO" << endl;
		return ;
	}
	step1 = cal(a);
	step2 = cal(b);
	if (step1 + step2 >= k)cout << "YES" << endl;
	else cout << "NO" << endl;
}
signed main() {
	int t ;
	euler();
	cin >> t;
	for (int i = 1; i <= t; i++)
		solve(i);
}

今天是我 \(20\) 岁生日,于是写了篇题解。

老年退役选手路过。

最后的最后

感谢观看,希望对你有所帮助。

posted @ 2025-04-16 19:47  LteShuai  阅读(18)  评论(0)    收藏  举报