【思路】取一个足够大的上限 $n$,确保最终答案不超过 $n$。我们可以采用欧拉筛得到所有的质数和合数表。注意合数不是按照顺序得到的,需要排序。
接着我们枚举所有在范围内的合数,二分找到不超过它的最大质数,然后判断二者之差是否能表示乘一个完全平方数的两倍即可。
总体时间复杂度为 $\mathcal O(n \log 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
| #include<bits/stdc++.h> using namespace std; const int maxn=100000; int prime[maxn],composite[maxn]; bool vis[maxn]; void euler() { vis[0]=vis[1]=true; for(int i=2;i<=maxn;++i) { if(!vis[i])prime[++prime[0]]=i; for(int j=1;i*prime[j]<=maxn&&j<=prime[0];++j) { vis[i*prime[j]]=true; if(i*prime[j]&1)composite[++composite[0]]=i*prime[j]; if(i%prime[j]==0)break; } } sort(composite+1,composite+composite[0]+1); } int binary(int l,int r,int x) { while(l<=r) { int mid=(l+r)>>1; if(prime[mid]>x)r=mid-1; else l=mid+1; } return r; } int main() { euler(); for(int i=1;i<=composite[0];++i) { int x=composite[i]; bool flag=false; for(int j=binary(1,prime[0],x);j>1;--j) { int y=prime[j],z=sqrt((x-y)>>1); if(z*z<<1==x-y) { flag=true; break; } } if(!flag) { printf("%d",x); return 0; } } return 0; }
|