BOZJ1528/POI 2005Toy Cars

假設地板上能放足夠多的玩具,那麼肯定一次性將所有玩具都拿下來.可是題目中有了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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章