1. 程式人生 > 其它 >牛客小白月賽39 G. 冷靜(樹狀陣列/線性篩)

牛客小白月賽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;
}