输入格式
第一行是一个整数T(1≤T≤10000),表示样例的个数。
以后每行两个整数a,b (1≤a≤b≤106)
输出格式
每行输出一个样例的结果,为一个整数。
样例输入
3 1 10 1 1000000 1000 2000
样例输出
21 424899695954 1099654
利用前缀和解题
标记素数
for(i=3;i<N;i++){
for(j=2;j*j<=i;j++){
if(i%j==0) break;
}
if(j*j>i) f[i]=1;
}
AC代码
#include<stdio.h>
#define N 1000005
#define ll long long
ll f[N]={};
void init(){
int i,j;
f[2]=1;
for(i=3;i<N;i++){
for(j=2;j*j<=i;j++){
if(i%j==0) break;
}
//标记素数
if(j*j>i) f[i]=1;
}
for(i=1;i<N;i++){
if(f[i]==1)f[i]=f[i-1]-i;
else f[i]=f[i-1]+i;
}
}
int main(){
int T;
scanf("%d",&T);
init();
while(T--){
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",f[b]-f[a-1]);
}
}
————————————————————————————————————————
二编:题目范围由10的6次方改为10的7次方,上面的代码会运行错误,数组范围扩大会超时。
用欧拉筛素数
欧拉筛法模板:思想 素数的倍数是合数
f[i]用来标记素数,b[i]用来存放素数
for(i=2;i<N;i++){
if(f[i]==0)b[k++]=i;
for(j=1;j<k;j++){
if(i*b[j]>N)break;
f[i*b[j]]=1;
if(i%b[j]==0)break;关键,保证一个数只被标记一次
}
}
if(i%b[j]==0)break;
这一步有点难理解,其实就是保证一个数只被其最小的质因数标记,如f[12]=1,最小质因数为2,i=6,f[6*2]=1
如果没有这一步,i=4时,f[4*3]=1被重复标记了
#include<stdio.h>
#define N 10000005
#define ll long long
ll f[N]={}; //不是素数标记为1
ll b[1000005]={}; //存放素数
void init(){
f[0]=1,f[1]=1;
int i,j,k=1;
for(i=2;i<N;i++){
if(f[i]==0)b[k++]=i;
for(j=1;j<k;j++){
if(i*b[j]>N)break;
f[i*b[j]]=1;
if(i%b[j]==0)break;//保证只被其最小的质因数标记
}
}
for(i=1;i<N;i++){
if(f[i]==0)f[i]=f[i-1]-i;
else f[i]=f[i-1]+i;
}
}
int main(){
int T;
scanf("%d",&T);
init();
while(T--){
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",f[b]-f[a-1]);
}
}