BZOJ1528: [POI2005]sam-Toy Cars
阿新 • • 發佈:2018-10-19
ans 而且 lin sim urn 一個 ... 可能 策略 而且他永遠不會成為堆頂(k = 1 不影響)
一開始是有不少 simple 的想法的...
比如剩余使用次數越多越優或者越少越劣這樣
隨便找找反例發現這顯然是不行的
比如一個點之前用的很少但在最後用的很多,
如果我還一直保留他那中間過程中的可用位置就變少了
可能會導致很多出現次數較少但比較集中的物品被反復拿多次
針對這種情況,有一個貪心策略就是下次出現的越早的物品留著越優
貌似也沒什麽反例(我也不會證明
這樣就每個需求記錄一下下一次出現的位置
用堆維護,在堆滿時將最劣的物品彈掉
這時我非常激動地無腦碼就 GG 成 10 pts 了
在仔細考慮會不會出鍋後,會發現如果在需要一個物品而它又恰好在堆中時,
什麽操作也不用做,但在這之後這個物品就永遠地留在了堆裏,
所以應該每次發現當前需求物品在堆中後 ++k
代碼:
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cctype> #include <cstdio> #include <queue> using namespace std; const int MAXN = 100005, MAXP = 500005; struct ITEM{ int nxt, id; ITEM(int NXT = 0, int ID = 0) {nxt = NXT; id = ID;} bool operator < (const ITEM& b) const { return nxt < b.nxt; } }; int n, k, p, ans; int req[MAXP], pos[MAXN], nxt[MAXP]; bool inq[MAXN]; priority_queue<ITEM> q; inline int rd() { register int x = 0; register char c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } int main() { n = rd(); k = rd(); p = rd(); for (int i = 1; i <= p; ++i) req[i] = rd(); for (int i = p; i; --i) { nxt[i] = ((pos[req[i]]) ? pos[req[i]] : (p + 1)); pos[req[i]] = i; } for (int i = 1; i <= p; ++i) { if (!inq[req[i]]) { if (q.size() == k) { inq[q.top().id] = false; q.pop(); } q.push(ITEM(nxt[i], req[i])); inq[req[i]] = true; ++ans; } else { ++k; q.push(ITEM(nxt[i], req[i])); } } printf("%d\n", ans); return 0; }
BZOJ1528: [POI2005]sam-Toy Cars