题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2098
对于这道题目需要掌握的就是如何高效的求小于整数n的素数有多少个,然后通过有技巧的遍历就可以很轻松的得到正确答案:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=1e4+5;
int prime[maxn];
int num=0;
void primes(int n)
{
int v[maxn];
memset(v,0,sizeof v);
for(int i=2;i<=n;i++)
{
if(v[i]==0){v[i]=i;prime[num++]=i;}
for(int j=0;j<num;j++)
{
if(prime[j]>v[i]||prime[j]>n/i) break;
v[i*prime[j]]=prime[j];
}
}
}
int main()
{
int n;
int ans;
while(scanf("%d",&n)&&n)
{
ans=0;memset(prime,0,sizeof prime);num=0;
primes(n);
sort(prime,prime+num);
int j=num-1;
for(int i=0;i<=num;i++)
{
for(;j>=0;j--)
{
if((prime[i]+prime[j])==n)
{
ans++;
//cout<<prime[i]<<' '<<prime[j]<<endl;
j=j-1;
break;
}
else if((prime[i]+prime[j])>n)
{
continue;
}
else if((prime[i]+prime[j])<n)
{
j=num-1;
break;
}
}
}
cout<<ans/2<<endl;
}
return 0;
}
分析:
我采用的是线性求解小于等于n 的素数个数的方法,复杂度是O(N)级别的,通过筛查,得到了一个素数数列,其实已经就是从小到大排序的了。这里有两个指针:i,j。
然后从最小的开始和最大的相加,倘若相等也就意味着可以i+1,j-1;倘若小于n,说明对于i来说j指向还不够大,所以i+1,j不变;倘若大于n,说明对于i来说,j指向有点大,可以continue,使j- -;