题目
时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
CHEN, Yue
令Pi表示第i个素数。现任给两个正整数M <= N <= 104,请输出PM到PN的所有素数。
输入格式:
输入在一行中给出M和N,其间以空格分隔。
输出格式:
输出从PM到PN的所有素数,每10个数字占1行,其间以空格分隔,但行末不得有多余空格。
输入样例:
5 27
输出样例:
11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103
题解
本来是个从小到大数素数的问题,不过测试的时候有个数据比较大,不能用弱智方法算了,或多或少得进行一点优化。考虑到这里不管怎么算都要从小到大把第N个素数以前所有的素数全部算出来(不然没法数第M个在哪里),那么这里就可以把每一个算出来的素数保存到一个集合里面去,在验证num是否素数的时候,先用这个集合里的元素来除一遍,全都除不尽的话再从集合中最大的元素开始遍历,到num/2为止。这种“手动打表”的方式可以在计算的时候节省很多时间(自学习哦亲~搭配文件操作的话越用越快哦亲~)。最终在那个最大的测试点花的时间是186ms,嘛~过了就行了┓( ´∀` )┏。
话说我本来在遍历后半部分的时候循环条件写的是
for(int count = begin; count <= end; count++)
后来改成了
for(int count = begin; count <= end; count += 2)
按理说时间应该可以缩短一些的,但是在那个测试点还是186ms。。。。可能是因为搭配上这个打表的方法的话需要更大的测试数据才可以吧。。。。还是说在验证素数的时候只要这样打了表,大部分的元素都不会超过前面一个的两倍吗?。。。。那就跑不到这部分验证了。。。
嘛。。反正过了。。。
代码
#include <bits/stdc++.h>
using namespace std;
vector<int> factor;
bool check (int num){
bool result = true;
int end = num/2, begin = -1;
if(!factor.empty()){
for(int ifac: factor){
if(num % ifac == 0){
result = false;
break;
}
}
begin = factor.back();
}
else
begin = 2;
for(int count = begin; count <= end; count += 2){
if(count > end || result == false){
break;
}
if((num % count) == 0){
result = false;
break;
}
}
return result;
}
int main(int argc, const char * argv[]) {
int N = -1, M = -1;
cin >> M >> N;
time_t a = clock();
int count = 0, num = 2, line = 0;
while(count < N){
if(check(num)){
factor.push_back(num);
if(count > M-1){
if(line % 10 == 0)
cout << endl;
else
cout << " ";
}
count++;
if(count > M-1){
cout << num;
line++;
}
}
num++;
}
return 0;
}