[POI2005]Toy Cars

题目大意:
  有n种物品,地上有k个格子,p次操作。
  每次操作要求将某一个指定的物品移动到任意一个格子中,同时你可以选择是否将格子中的某一个物品收起来,并消耗1的代价。
  如果下达指令时,这个物品刚好在格子上,那么就不会消耗代价。
  问至少消耗多少代价?

思路:
  贪心。
  每次移动如果时,如果地板上已经放慢了物品,那么就应该把第二次出现最晚的物品收起来。
  预处理每一次指令对应的物品第二次出现的时刻。
  用一个堆来维护当前地板上的物品即可。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<hash_set>
 4 #include<ext/pb_ds/priority_queue.hpp>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int N=100001,P=500001;
13 int a[P],cnt[N],pos[N],next[P];
14 __gnu_cxx::hash_set<int> set;
15 __gnu_pbds::priority_queue<std::pair<int,int> > q;
16 __gnu_pbds::priority_queue<std::pair<int,int> >::point_iterator p[N];
17 int main() {
18     const unsigned n=getint(),k=getint(),p=getint();
19     for(register unsigned i=1;i<=p;i++) {
20         a[i]=getint();
21         cnt[a[i]]++;
22     }
23     for(register unsigned i=1;i<=n;i++) pos[i]=p+1;
24     for(register unsigned i=p;i;i--) {
25         next[i]=pos[a[i]];
26         pos[a[i]]=i;
27     }
28     unsigned ans=0,i=1;
29     for(;set.size()<k&&set.size()<n&&i<=p;i++) {
30         if(!set.count(a[i])) {
31             ans++;
32             set.insert(a[i]);
33             ::p[a[i]]=q.push(std::make_pair(next[i],a[i]));
34         } else {
35             q.modify(::p[a[i]],std::make_pair(next[i],a[i]));
36         }
37     }
38     for(;i<=p;i++) {
39         if(!set.count(a[i])) {
40             ans++;
41             set.erase(q.top().second);
42             q.pop();
43             set.insert(a[i]);
44             ::p[a[i]]=q.push(std::make_pair(next[i],a[i]));
45         } else {
46             q.modify(::p[a[i]],std::make_pair(next[i],a[i]));
47         }
48     }
49     printf("%u\n",ans);
50     return 0;
51 }

 

posted @ 2017-12-20 20:30  skylee03  阅读(123)  评论(0编辑  收藏  举报