[POI2005]SAM-Toy Cars
题意:
好像题意已经挺明白的了,戳。
解法:
首先来想一下如何才能尽量少的取玩具. 显然,如果一个玩具已经在地上了,就可以不用去取. 但是地上能放的玩具的数量有限,所以我们可以记录每种玩具下一次要被玩的时间next[i],并在需要更换玩具的时候换走当前队列中next[i]最大的那一个玩具.
所以我们可以得到这样一个贪心策略:要换玩具的时候,换next[i]最远的那个玩具。
然后就是模拟一下入队出队情况,用优先队列维护一下next。
CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define N 500010
#define M 100010
int n,k,p,a[N];
int nxt[N],ans;
bool vis[M];
struct cmp {
inline bool operator() (const int &a,const int &b) {
return nxt[a] < nxt[b];
}
};
queue <int> q1[M];
priority_queue <int,vector<int>,cmp> q2;
int main() {
scanf("%d%d%d",&n,&k,&p);
for(int i = 1 ; i <= p ; i++) {
scanf("%d",&a[i]);
q1[a[i]].push(i);
}
for(int i = 1 ; i <= p ; i++) {
q1[a[i]].pop();
if(q1[a[i]].empty()) nxt[i] = p + 1;
else nxt[i] = q1[a[i]].front();
}
for(int i = 1 ; i <= p ; i++) {
if(!vis[a[i]]) {
if(q2.size() == k) {
vis[a[q2.top()]] = 0;
q2.pop();
}
q2.push(i);
vis[a[i]] = 1;
ans++;
}
else q2.push(i), k++;
}
printf("%d
",ans);
//system("pause");
return 0;
}