题目背景
题目名称是吸引你点进来的
实际上该题还是很水的
题目描述
区间质数个数
输入输出格式
输入格式:
一行两个整数 询问次数n,范围m
接下来n行,每行两个整数 l,r 表示区间
输出格式:
对于每次询问输出个数 t,如l或r∉[1,m]输出 Crossing the line
输入输出样例
输入样例#1:
2 5
1 3
2 6
输出样例#1:
2
Crossing the line
说明
【数据范围和约定】
对于20%的数据 1<=n<=10 1<=m<=10
对于100%的数据 1<=n<=1000 1<=m<=1000000 -10^9<=l<=r<=10^9 1<=t<=1000000
题目地址:https://www.luogu.org/problemnew/show/P1865
个人思路:
- 第一眼看过去感觉是个线性筛的裸题,不过发现还附带了一个区间查询
- 关于区间查询的实现方式,粗略地想了一下,感觉DP的方式不是太好写,就写了一个树状数组
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int n,m;
int vis[1000001];
int tr[1000001];
int lowbit(int a){
return a&-a;
}
int add(int a,int x){
for(int i=a;i<=m;i+=lowbit(i))tr[i]+=x;
}
int sum(int a,int b){
if(a>b)swap(a,b);
int ans=0;
for(a--;a;a-=lowbit(a))ans-=tr[a];
for(;b;b-=lowbit(b))ans+=tr[b];
return ans;
}
int main(){
cin>>n>>m;
memset(vis,0,sizeof(vis));
int total=sqrt(m+0.5);
vis[1]=1;
add(1,1);
for(int i=2;i<=total;i++)
if(!vis[i])
for(int j=i*i;j<=m;j+=i)
if(!vis[j]){
vis[j]=1;
add(j,1);
}
for(int i=1;i<=n;i++){
int ta,tb;
cin>>ta>>tb;
if(ta>tb)swap(ta,tb);
if(tb>m||ta>m||ta<1||tb<1){
printf("Crossing the line\n");
continue;
}
cout<<tb-ta+1-sum(ta,tb)<<endl;
}
return 0;
}