假设地板上能放足够多的玩具,那么肯定一次性将所有玩具都拿下来.可是题目中有了k这个限制.为了完成题目的要求,不得不将某些玩具拿回去,使得新玩具有地方放置.那么问题就是将什么玩具拿回去.如果某个玩具x之后不再出现,那么一定将它拿走,既不会对答案产生影响,又有利于以后的玩具放置.万一没有不再用的玩具了,只能将某个暂时不玩但以后还要玩的玩具y,要选择的是下一次出现的时间最晚的玩具y.
对于每个y,拿回架子之后都要在y下一次被选中之前再次放回地板,至少要再操作一次,若下一次被选中的时间很早,就有可能在选中后又要放回,显然是不够优的.因此选择下一次出现时间最晚的玩具.
利用优先队列维护下一次出现时间最晚的玩具.
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int M=1e5+5;
int n,m,p,on[M],pre[M],nex[M*5];
struct node{
int id,t;
bool operator<(const node &tmp)const{
if(t!=tmp.t)return t<tmp.t;//从大.
return id<tmp.id;
}
}A[M*10];
inline void rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c>=48);
}
priority_queue<node>Q;
int main(){
int i,j,k;
rd(n);rd(m);rd(p);
for(i=1;i<=p;i++){
rd(A[i].id);
A[i].t=i;
if(pre[A[i].id])nex[pre[A[i].id]]=i;
pre[A[i].id]=i;
}
int tot=p;
for(i=1;i<=n;i++){
if(pre[i])A[++tot]=(node){-i,pre[i]+1};
}
sort(A+1,A+1+tot);
int now=0,cnt=0,ans=0;//当前可以拿走的个数
for(i=1;i<=tot;i++){
int id=A[i].id,t=A[i].t;
if(id<0){
cnt++;on[-id]=0;
continue;
}
else if(!on[id]){
ans++;
if(cnt)cnt--;
else if(now<m)now++;
else {
node x;
do {x=Q.top();Q.pop();}
while(!on[x.id]);
on[x.id]=0;
}
on[id]=1;
}
if(nex[t])Q.push((node){id,nex[t]});
}
printf("%d\n",ans);
return 0;
}