内容:
我们来定义下一个数的素数价值,假设这个数是N(2<=N<=50000),我们可以通过以下两种方法:
1.把当前数字除以某个素数(当然得可以整除),即N = N / p;
2.把当前数字减去某个素数(保证减后结果为正整数),即N = N - p;
这个数字的素数价值是最少得通过多少次以上的方法使得它变成0.
第一行是测试数据的组数T,接着有T组测试数据.每组测试数据有两个数字a,b(2<=a<=b<=50000).
对于每组测试数据,输出区间[a,b]之间所有数字的素数价值的和.
思路:
利用哥德巴赫猜想:偶数=2素数和;
但是,当为奇数时:需要考虑第一种情况,将50000以内素数打表(打表只需到sqrt(50000)即可),看当前值是否能整除开一个素数;
当整除开一个素数后又分俩情况:当除得结果:(1)也为素数;(2)不为素数;
最后把所有算的数的和都预处理到一个数组中即:table[i]:1~i的价值和,最后直接求table[b]-table[a-1]即可
代码:
#include <iostream>
#include <cstdio>
#include <math.h>
using namespace std;
bool judge(int n){//判断素数
if(n<=1) return false;
if(n == 2 || n == 3) return true;
if(n % 6 != 1 && n % 6 != 5) return false;
for(int i=5;i<sqrt(n)+1;i+=6) if(n % i == 0 || n % (i+2) == 0) return false;
return true;}
int table[50005],prime[500],num;
void pretreatment(){//将srqt(50000)素数找到
for(int i=2;i<=sqrt(50000);i++) if(judge(i)) prime[num++] = i;
}
void fun(){
int cot = 0;
for(int i=2;i<=50000;i++)
{
if(judge(i)) cot++;//本身为素数
else
{
if(i % 2 == 0) cot += 2;//偶数=2个素数:哥德巴赫猜想
else
{
int temp = i;
if(judge(temp-2)) cot+=2;//当奇数时,减去一个素数后,另一个已素数
else
{
int j;for(j=0;j<num;j++)//可能出现除以一个素数
{
if(temp % prime[j] == 0)
{
int tt = temp/prime[j];
if(judge(tt)) cot+=2;//除以一个素数后另一个也为素数
else cot += 3;//另一个不为素数
break;
}
}
if(j == cot) cot += 3;//不能整除素数的,只能化为一个偶数+一个素数
}
}
}
table[i] = cot;//将每个位置预处理成1~i的所有价值和
}
return;}
int main()
{
int t,a,b;
pretreatment();fun();
scanf("%d",&t);
while(t--){
scanf("%d%d",&a,&b);
printf("%d\n",table[b]-table[a-1]);
}
return 0;
}