牛客小白月赛39 G. 冷静(树状数组/线性筛)
链接:https://ac.nowcoder.com/acm/contest/11216/G
来源:牛客网
题目描述
想去实现宏大的梦想 向着那遥不可及的地方
想在那一片纯白的世界 留下我最初的脚印
在世界的终端 太阳在永不停息地运转
南风终将吹过小岛 轻抚我的柔发
想去实现心底小小的梦
——《ハルカトオク》
痛定思痛,奋楫争先再出发……
q 次询问。每次询问给定 n 和 K,问 1 ~ n 中有多少数可以表示为大于等于 K 的质数的乘积(一个数可以乘多次)。
输入描述:
第一行读入一个整数q
接下来q行每行读入2个整数,第i行表示 niniKiKi
1≤q≤3e61≤q≤3e6,1≤ni,Ki≤3e61≤ni,Ki≤3e6。
输出描述:
q行,共 q 个数,分别表示 q 次询问的答案。
示例1
输入
复制
1
100 5
输出
复制
32
示例2
输入
复制
2
20 3
10 5
输出
复制
9
2
暴力做法就是把每个数唯一分解掉,每个查询暴力统计。考虑如何优化。首先,1到n每个数的最小质因子可以通过线性筛\(O(n)\)地求出来,但是这样对于每次查询的复杂度也是\(O(n)\)的,需要继续优化。因为整体值域比较小,可以借助树状数组维护,离线处理询问。具体来说,首先读入所有的询问并按照n从小到大进行排序并处理,然后维护一个变量num,每处理到一个询问,当num小于这个询问的k值的时候就不断把num这个数的最小质因子插入树状数组维护的桶然后把num++。最后\(O(log(n))\)查询答案并更新到答案数组。
注意这个题卡了一波cout
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int prime[10000005], primesize, phi[10000005], mn[10000005];
bool isprime[10000005];
int read() {
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
void getlist(int listsize) {
for(int i = 1; i <= 3000002; i++) isprime[i] = 1, mn[i] = 0x3f3f3f3f;
isprime[1] = false;
for(int i = 2; i <= listsize; i++) {
if(isprime[i]) prime[++primesize] = i, mn[i] = i;
for(int j = 1; j <= primesize && i * prime[j] <= listsize; j++) {
isprime[i * prime[j]] = false;
mn[i * prime[j]] = min(mn[i * prime[j]], prime[j]);
if(i % prime[j] == 0) break;
}
}
}
struct ask {
int n, k, id;
bool operator < (const ask& o) const {
return n < o.n;
}
};
int ans[3000005];
int b[3000005];
void modify(int x, int y) {
for(; x <= 3000000; x += (x & -x)) {
b[x] += y;
}
}
int query(int x) {
int ans = 0;
for(; x; x -= (x & -x)) {
ans += b[x];
}
return ans;
}
int main() {
getlist(3000000);
int q;
cin >> q;
vector<ask> v;
for(int i = 1; i <= q; i++) {
int n, k;
n = read(), k = read();
ask tmp = {n, k, i};
v.push_back(tmp);
}
sort(v.begin(), v.end());
int num = 2;
for(auto a : v) {
while(num <= a.n) {
modify(mn[num], 1);
num++;
}
ans[a.id] = query(a.n) - query(a.k - 1);
}
for(int i = 1; i <= q; i++) {
printf("%d\n", ans[i]);
}
return 0;
}