P1865 A % B Problem
题目
题目描述
区间质数个数
输入格式
一行两个整数 询问次数n,范围m
接下来n行,每行两个整数 l,r 表示区间
输出格式
对于每次询问输出个数 t,如l或r∉[1,m]输出 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
分析
- 实际上那个l,r是用来蒙人的,真正需要计算的范围由m决定
真正的l,r范围为[1, 1000000],即m - 虽然数据范围没有看起来那么大,但是这种范围不用线性筛还是容易TLE
(详见这里) - 询问的是区间内质数的个数,可以用一个树状数组来统计(貌似某种超强线段树也行)
d[i]用来统计[1…i]中的质数个数
(详见这里)
AC Code
说实话我都快把线性筛忘了,成功华丽的暴了个零
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1000000;//最大范围
const int maxprime = 1e6;//实际上不会出现这么多素数
bool isPrime[maxn];//线性筛的数据
int prime[maxprime], n, m, t;
int d[maxn];//树状数组的数据
int lowbit(int x) {//树桩数组核心
return x&(-x);
}
void update(int x, int v) {//在x处有v个素数(v=1)即x是素数
while(x<=m) {
d[x]+=v;
x+=lowbit(x);
}
}
int query(int x) {//查询[1...x]的素数总数
register int sum = 0;
while(x) {
sum+=d[x];
x-=lowbit(x);
}
return sum;
}
int main() {
/*一点也不优的优化*/
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
/*线性筛*/
memset(isPrime, true, sizeof isPrime);
isPrime[0] = isPrime[1] = false;
for(int i=2; i<=m; i++) {
if(isPrime[i]) {
prime[++prime[0]] = i;
update(i, 1);//树状数组,i是素数
}
for(int j=1; j<=prime[0] && i*prime[j]<=m; j++) {
isPrime[i*prime[j]] = false;
if(i%prime[j]==0) break;
}
}
/*处理询问*/
int l, r;
for(int i=0; i<n; i++) {
cin>>l>>r;
/*
越界判断:
l或r∉[1,m]
*/
if(l<1||l>m) {
cout<<"Crossing the line"<<endl;
continue;
}
if(r<1||r>m) {
cout<<"Crossing the line"<<endl;
continue;
}
/*
输出答案,详见树桩数组的使用
l必须-1
*/
cout<<query(r)-query(l-1)<<endl;
}
return 0;
}