[NOIP2015四校联训Day8]质数生成器
时间限制:1000MS 内存限制:131072KB
-
题目描述
生成给定范围内的所有质数。
-
输入格式
有多组数据。
输入数据第一行是一个整数\(T(T\leq10)\),表示测试数据的组数。
接下来\(T\)行,每行有两整数\(m, n\),表示要求生成质数的范围是\([m, n] (1 \leq m \leq n \leq 10^9, n-m \leq 10^6)\)
-
输出格式
对于每一组测试数据,输出所有在\([m, n]\)中的质数\(p\),一行一个。
不同测试数据之间用一个空行分隔。
-
样例输入
1 2 3 |
2 1 10 3 5 |
-
样例输出
1 2 3 4 5 6 7 |
2 3 5 7 3 5 |
-
数据规模与约定
对于\(30\%\)的数据,\(m < n \leq 10^3\);
对于\(50\%\)的数据,\(m < n \leq 10^6 且 n-m \leq 10^3\);
对于\(100\%\)的数据,\(m < n \leq 10^9 且 n-m \leq 10^6\);
看到\(m < n \leq 10^9\)直接被吓到了,但其实注意到\(n-m \leq 10^6\)条件,说明我们只要输出最多\(10^6\)个质数,这是可以接受的。
显然我们无法存下所有的数直接判断,因为空间\(sizeof(int) \cdot 10^9 Bytes \approx 3814 MB\)且时间预处理\(O(N\leq10^9)\)这是无法接受的。所以我们考虑先记下前面几个质数,后面的数就用前面的质数来筛就行。
先用线性筛筛出前几个数的质数,比如我筛到\(10^6\)比较保险,对于每次询问的\(m, n\),如果区间\([m, n]\)与\([1, 10^6]\)有交集,可以很开心的输出在\([1, 10^6]\)区间里的质数。
如果区间\([m, n]\)还有超出区间\([1, 10^6]\)的部分,因为其长度最大为\(10^6\)(\(n-m \leq 10^6\)),我们可以开一个\(10^6\)的数组保存当前这个数是否被之前的质数筛过。然后遍历之前我们筛出来的每一个质数,找到这个质数的所有在当前区间\([max(m, 10^6+1), n]\)的所有倍数打上标记,这样循环结束之后再对区间里的数遍历,没有被打上标记的即为质数,输出即可。
程序实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#include <cstdio> #include <cstdlib> #include <cstring> #define NUM 1050505 int num[NUM+1]; int prs[NUM+1]; int tn; bool tmn[NUM+1]; int main() { int T;scanf("%d",&T); for(register int i=2;i<=NUM;i++) { if(!num[i]) prs[tn++]=i; for(register int j=0;j<tn;j++) { if(prs[j]*i<=NUM) num[prs[j]*i]=1; else break; if(i%prs[j]==0) break; } } for(register int lp=1;lp<=T;lp++) { int l,r;scanf("%d%d",&l,&r); memset(tmn,0,sizeof(tmn)); if(l<=NUM) { for(register int j=0;j<tn;j++) if(prs[j]<=r) { if(prs[j]>=l) printf("%d\n",prs[j]); } else break; } if(r>NUM) { if(l<=NUM) l=NUM+1; for(register int j=l;j<=r;j++) tmn[j-l]=true; for(register int j=0;j<tn;j++) { int npm=prs[j]; int st=l/npm*npm; for(register int k=st;k<=r;k+=npm) { if(k<l) continue; tmn[k-l]=false; } } for(register int j=l;j<=r;j++) if(tmn[j-l]) printf("%d\n",j); } printf("\n"); } return 0; } |