LGP10647 [NordicOI 2023] Ice Cream Machines 学习笔记

LGP10647 [NordicOI 2023] Ice Cream Machines 学习笔记

Luogu Link

题意简述

\(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;
}
posted @ 2025-08-24 14:56  矞龙OrinLoong  阅读(5)  评论(0)    收藏  举报