题解 AT5249 [ABC149C] Next Prime
介绍一种比较新颖的方法。
首先,我们先定义一个数组:a,用来存储
判断质数的方法有很多,由于本题的数据范围较小,可以直接使用
试除法原理:
对于一个数,一定有至少两个因数(
我们可以尝试去找到除这两个因数以外的因数。举个例子:
这个例子中,标红的因数为「除这两个因数以外的因数」。
根据一个质数必定只有两个因数:
所以,我们才会找其他的因数,如果找到了,证明这个数不是质数;如果没有找到,这个数就是质数。
可得代码:
bool prime(int a)
{
for(int i = 2; i <= n; i++) if(a % i == 0) return 0;
return 1;
}
但是,这个代码的时间复杂度是
观察刚刚
颜色相同的因数为「一对」,这两个数相乘等于
整数的因数成对出现(完全平方数除外)。
还可以试着用其他的数进行证明,这里不再赘述。
为什么完全平方数除外呢?举个例子:
此处,
所以,还有一个定理:完全平方数的因数有奇数个。
由于因数是成对出现的,所以只要一个数能被「一半的」因数整除,必然能被「另一半的」因数整除(完全平方数除外)。
根据这个定理,可以直接枚举到
写成代码:
bool prime(int a)
{
for(int i = 2; i * i <= n; i++) if(a % i == 0) return 0;
return 1;
}
不推荐在此处使用 sqrt 函数,以免发生奇奇怪怪的错误。
再回到开头的方法,把 a 数组求出来,范围是
可写出代码(轻微压行):
const int N = 1e5 + 5;
int a[N], cnt;
for(int i = 1; i <= N; i++) if(prime(i)) a[++cnt] = i;
由于我的下标习惯从 ++cnt 而不是 cnt++。使用后者会先存储,在更新 cnt,适合从
接下来,输入 n 以后,直接查表即可。
代码:
for(int i = 1; i <= cnt; i++)
{
if(a[i] >= n)
{
cout << a[i] << endl;
break;
}
}
把上述几个代码块拼接起来就是 AC 程序了,时间复杂度 N 个数是否为质数,所以复杂度为常量)。读者还可以了解更多的质数筛法,如线性筛、埃氏筛、欧拉筛等高效率的筛法。