AcWing 196. 质数距离
考察:质数筛
一开始是在POJ上做的,感谢AcWing让我看到错误数据555
思路:
朴素筛肯定不行.但这道题数字范围很大以至于数字难以用数组存储.好在题目提示r与l的范围差不超过1000000.这样可以将数组下标偏移,这样就能利用筛法求区间素数
这道题要求出质数距离,也就是我们需要先求出范围内的素数.考虑到是多组输入.我们利用筛法筛掉合数是利用合数的最小质因数.所以我们可以预处理INT_MAX范围内的最小质因数.朴素筛法说明最小质因数不会超过√INT_MAX.我们预处理这部分的质因数即可
接下来是利用质因数筛掉l,r范围内的合数.利用埃氏筛法即可
易错:
注意l,r虽然都在int范围内,但必须声明为ll类型.否则埃氏筛的时候j<=r会RE
l==1的时候需要特判,否则1也会被记录
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int N = 1000010,M = 50000; 6 typedef pair<int,int> pii; 7 typedef long long ll; 8 int prime[M],cnt,ans[N],k; 9 bool st[M],vis[N]; 10 long long l,r; 11 void inits() 12 { 13 memset(vis,0,sizeof vis); k = 0; 14 } 15 void GetPrime(int n) 16 { 17 for(int i=2;i<=n;i++) 18 { 19 if(!st[i]) prime[++cnt] = i; 20 for(int j=1;prime[j]<=n/i;j++) 21 { 22 st[i*prime[j]] = 1; 23 if(i%prime[j]==0) break; 24 } 25 } 26 } 27 void Getans() 28 { 29 for(ll i=l;i<=r;i++)//r在int边界,i+1刚好越界 30 if(!vis[i-l]) ans[k++] = i; 31 } 32 int main() 33 { 34 // freopen("in.txt","r",stdin); 35 GetPrime(48500); 36 while(scanf("%lld%lld",&l,&r)!=EOF) 37 { 38 inits(); 39 pii p[2]; 40 int minv = 0x3f3f3f3f,maxn = -1; 41 for(int i=1;i<=cnt;i++) 42 { 43 for(ll j=max(2ll,(ll)(l+prime[i]-1)/prime[i])*prime[i];j<=r;j+=prime[i]) 44 vis[j-l] = 1; 45 } 46 if(l==1) vis[0] = 1; 47 Getans(); 48 for(int i=0;i<k;i++) 49 { 50 if(i&&ans[i]-ans[i-1]<minv) 51 { 52 minv = ans[i]-ans[i-1]; 53 p[0].first = ans[i-1],p[0].second = ans[i]; 54 } 55 if(i&&ans[i]-ans[i-1]>maxn) 56 { 57 maxn = ans[i]-ans[i-1]; 58 p[1].first = ans[i-1],p[1].second = ans[i]; 59 } 60 } 61 if(k<=1) puts("There are no adjacent primes."); 62 else{ 63 printf("%d,%d are closest, %d,%d are most distant.\n",p[0].first,p[0].second,p[1].first,p[1].second); 64 } 65 } 66 return 0; 67 }
2021.01.24 把代码换成了再写一遍的代码
有几个错误还是犯了:
- l=1的特例,脑子记得但处理还是处理错了,不能在inits()里直接初始化,这样会导致如果l为质数就会错误
- 大数据还是段错误了,原因在注释里标明了,数据在范围边界来回试探的变量直接开long long