牛客小白月賽39 G. 冷靜(樹狀陣列/線性篩)
阿新 • • 發佈:2021-10-23
連結: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; }