CF17A Noldbach problem 题解
传送门
题目分析
这道题需要运用素数筛的知识。
我们可以用数组 (prime) 来存储在 (2)~(n) 中所有的素数。存储素数可以用线性筛素数。
void primes(int n)
{
memset(v,0,sizeof(v));//最小质因子
cnt=0;//质数个数
for(int i=2;i<=n;i++)
{
if(!v[i])//未被标记,i为质数
{
v[i]=i;
prime[++cnt]=i;
}
for(int j=1;j<=cnt;j++)
{
if(prime[j]>v[i]||prime[j]>n/i) break;//i有更小的质因子,或者超出n的范围
v[i*prime[j]]=prime[j];//prime[j]为合数 i*prime[j]的最小质因子
}
}
}
之后,我们要判断这些素数里哪些是“好素数”。“好素数”是在数值比它小的素数中,只要能找到两个相邻的素数,且这两个相邻素数之和+1 等于 “好素数”的数值,那么它就是好素数。
由于数据范围 (2leq nleq 1000) ,所以我们可以用 (O(n^2)) 来暴力搜出来好素数。只要搜到,就把它存入数组 (x) 中。
for(int i=3;i<=cnt;++i)
for(int j=1;j<=i-2;++j)
{
if(prime[j]+prime[j+1]+1 == prime[i])
x[++tot]=prime[i];
}
最后,我们只要判断 (x) 数组存储的数的个数是否大于 (k) 即可。
这道题还有一些细节,详见代码部分。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int n,k,cnt,ans,prime[1005],tot=0;
int x[1005],v[1005];
void primes(int n)//线性筛素数
{
memset(v,0,sizeof(v));//最小质因子
cnt=0;//质数个数
for(int i=2;i<=n;i++)
{
if(!v[i])//未被标记,i为质数
{
v[i]=i;
prime[++cnt]=i;
}
for(int j=1;j<=cnt;j++)
{
if(prime[j]>v[i]||prime[j]>n/i) break;//i有更小的质因子,或者超出n的范围
v[i*prime[j]]=prime[j];//prime[j]为合数 i*prime[j]的最小质因子
}
}
}
int main()
{
memset(x,0x3f3f3f,sizeof x);
/*
这里把x初始化为一个很大的值,因为最后要判断n和x数组的大小。
如果x数组中的数都小于n,则下一个数需要为一个最大值,以记录答案个数。
*/
cin>>n>>k;
primes(n); //线性筛素数
for(int i=3;i<=cnt;++i)
for(int j=1;j<=i-2;++j)
{
if(prime[j]+prime[j+1]+1 == prime[i])
x[++tot]=prime[i]; //筛出“好素数”
}
for(int i=1;i<=tot+1;++i)
if(x[i]>n)
{
ans=i-1; //判断在范围内有几个“好素数”
break;
}
if(ans>=k) cout<<"YES"; //最后和k作比较,输出答案
else cout<<"NO";
}