2017ecjtu-summer training #7 POJ 2689
Posted 灬从此以后灬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017ecjtu-summer training #7 POJ 2689相关的知识,希望对你有一定的参考价值。
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 18731 | Accepted: 5006 |
Description
Your program is given 2 numbers: L and U (1<=L< U<=2,147,483,647), and you are to find the two adjacent primes C1 and C2 (L<=C1< C2<=U) that are closest (i.e. C2-C1 is the minimum). If there are other pairs that are the same distance apart, use the first pair. You are also to find the two adjacent primes D1 and D2 (L<=D1< D2<=U) where D1 and D2 are as distant from each other as possible (again choosing the first pair if there is a tie).
Input
Output
Sample Input
2 17 14 17
Sample Output
2,3 are closest, 7,11 are most distant. There are no adjacent primes.
题意:输入区间[l,u],其中l和u为int范围的整数,区间最大为1000000。求出[l,u]中,相邻素数只差最大和最小的素数对。当存在多个时,输出较小的素数对。
题解:l,u范围太大,不能直接求int范围的素数。而区间间隔比较小,只有1e6,而且对于int范围内的合数来说,最小质因子必定小于2^16。所以可以求出[l,u]中合数,转而求出素数,然后暴力枚举所有素数对即可。
如何求区间[l,u]中的合数:上面已经说了,合数的最小质因子小于2^16,即小于50000。所以先求出小于50000的所有素数。则区间[l,u]中的合数,必定可以表示为小于50000的素数的倍数。对于素数p来说,令a=(l-1)/p+1,b=u/p。则枚举j=a到b,j*p可以枚举所有[l,u]中质因子含有p的合数。枚举所有小于50000的素数,然后用上述方式枚举倍数,即可找出[l,u]中所有的合数。
由于l,u在int范围,所以不能直接用数组标记。需要加个偏移量,取l,则数组大小小于1e6的f[0,u-l],即可标记。
接着枚举区间中所有的相邻素数对即可。
特别注意:由于1不是小于50000的素数的倍数,所以在与合数相斥中,会被当成素数。需要特别处理下。
AC代码
1 #include <stdio.h> 2 #include <math.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <iostream> 6 #include <sstream> 7 #include <queue> 8 #include <vector> 9 #include <algorithm> 10 #define maxn 50010 11 #define maxm 1000010 12 #define inf 0x3f3f3f3f 13 using namespace std; 14 typedef long long ll; 15 int vis[maxm],f[maxm]; 16 int prime[maxn],prime1[maxm]; 17 int mind,maxd,minl,minr,maxl,maxr; 18 int t,t1; 19 ll L,R; 20 void init() //筛选出50000以内的素数 21 { 22 t=0; 23 memset(vis,0,sizeof(vis)); 24 for(int i=2;i<maxn;i++) 25 { 26 if(!vis[i]) 27 { 28 prime[t++]=i; 29 for(int j=i+i;j<maxn;j+=i) 30 vis[j]=1; 31 } 32 } 33 } 34 void selet() 35 { 36 memset(vis,0,sizeof(vis)); //*特别考虑1 37 for(int i=0;i<t;i++) //标记int范围内的合数 38 { 39 ll b=L/prime[i]; 40 while(b*prime[i]<L||b<=1) 41 b++; 42 for(ll j=b*prime[i];j<=R;j+=prime[i]) 43 vis[j-L]=1; //节约空间,降低空间复杂度 44 } 45 if(L==1) 46 vis[0]=1; 47 t1=0; 48 for(ll i=L;i<=R;i++) //找出区间内的素数存进数组 49 { 50 if(!vis[i-L]) 51 prime1[t1++]=i; 52 } 53 } 54 void solve() 55 { 56 selet(); 57 mind=inf,maxd=-inf; 58 minl=minr=maxl=maxr=-1; 59 for(int i=1;i<t1;i++) //枚举区间内的素数,更新要输出的值 60 { 61 int d=prime1[i]-prime1[i-1]; 62 if(d<mind) 63 { 64 mind=d; 65 minl=prime1[i-1]; 66 minr=prime1[i]; 67 } 68 if(d>maxd) 69 { 70 maxd=d; 71 maxl=prime1[i-1]; 72 maxr=prime1[i]; 73 } 74 } 75 } 76 int main(int argc, char const *argv[]) 77 { 78 init(); 79 while(cin>>L>>R) 80 { 81 solve(); 82 if(t1<2) 83 printf("There are no adjacent primes.\n"); 84 else 85 printf("%d,%d are closest, %d,%d are most distant.\n",minl,minr,maxl,maxr); 86 } 87 return 0; 88 }
以上是关于2017ecjtu-summer training #7 POJ 2689的主要内容,如果未能解决你的问题,请参考以下文章
2017ecjtu-summer training #7 POJ 2689
2017ecjtu-summer training # 9 HDU 4544
2017ecjtu-summer training #4 UESTC 30
2017ecjtu-summer training #3 POJ3264