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})\)。
- 时间复杂度:\(O(\sqrt{N})\)
- 最大检查的质因数: \(\sqrt{10^{12}} = 10^6\)
- 检查次数: 大约是 \(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}\) 个。
-
时间复杂度: \(O\left(\frac{2 \sqrt{N}}{\ln N}\right)\)
-
最大检查的质因数: \(\sqrt{10^{12}} = 10^6\)
-
在范围 ([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\) 岁生日,于是写了篇题解。
老年退役选手路过。
最后的最后
感谢观看,希望对你有所帮助。

浙公网安备 33010602011771号