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;
}
展开阅读全文

没有更多推荐了,返回首页