LGP10647 [NordicOI 2023] Ice Cream Machines 学习笔记
LGP10647 [NordicOI 2023] Ice Cream Machines 学习笔记
题意简述
有 \(k\) 个初始为白色的物块与 \(m\) 种非白色的颜色。\(n\) 个有时间顺序的任务,每个都要求你在当前全局中存在一个为 \(c_i\) 颜色的物块。问至少要染色多少次。
\(n,m,k\le 2\times 10^5\)。
做法解析
贪心策略是好想的:对于 \(c_i\),场上若已有此种颜色就不用染。否则肯定染白的。再否则,如果一个颜色在此后再也没有要求出现,就把它换掉,再再否则……选取下一个需求离当前最远的颜色染掉。
你可能不一定能直观感受到它优。我们来举个例子:\(k=3,m=4\),序列为 \(\texttt{12342342341}\)。显然到了第一个 \(4\) 出现的时候,所有颜色在后面都还要出现,但你显然会选择把 \(1\) 染掉。
感性理解,如果在一个已经有 \(k\) 种颜色的场面上,我们出现了颜色 \(k+1\),要选择之前的一个颜色换掉。若 \(b\) 下一次出现比 \(a\) 晚,我们换 \(b\) 相比换 \(a\),就有更大的时长不用考虑“被换掉的颜色怎么办”。而这个最优性是和其它颜色互不相关的。
用优先队列即可简单实现。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=2e5+5;
int N,M,K,C[MaxN],apr[MaxN],nxt[MaxN];
bool vld[MaxN];int cnt,ans;
priority_queue<pii> pq;
int main(){
readis(N,M,K);
for(int i=1;i<=N;i++){
readi(C[i]),nxt[apr[C[i]]]=i;
apr[C[i]]=i,nxt[i]=N+1;
}
for(int i=1;i<=N;i++){
if(vld[C[i]]){pq.push({nxt[i],C[i]});continue;}
if(cnt==K){auto [ct,cc]=pq.top();vld[cc]=0,pq.pop();}
cnt=min(cnt+1,K),pq.push({nxt[i],C[i]}),vld[C[i]]=1,ans++;
}
writi(ans);
return 0;
}
浙公网安备 33010602011771号