假設地板上能放足夠多的玩具,那麼肯定一次性將所有玩具都拿下來.可是題目中有了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;
}