题目大意:
有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 ",ans); 50 return 0; 51 }