STL + 贪心
题意:
ACM-ICPC赛事上有n,1~n道题,m个模板(1~m),只有对应的模板才能解出对应的题目,现在规则有点改变,当你没有某一道题的模板的时候能从场外求助获得此模板,但是用完之后你需要从m+1个模板中拿出来一个放在外边,总之就是要保持自己只有m 个模板,问最少可以求助几次?
思路:
若想最少次,那么可以先考虑当模板不够的时候求助一次,然后再放出去一个模板,该放哪一个呢?
自然是用到的模板最靠后的那一个,因为在此之前你还需要用其它模板。
所以贪心思想已经有了,如何实现?
首先肯定需要记录m个模板和使用的下一次的位置,set不能放重复元素,但是可以存放模板保留情况,以便快速查找。multiset可以借用排序,从而快速找到和重置模板的信息。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
using namespace std;
const int maxn = 100005;
int a[maxn],n,m;
int Next[maxn];
struct Template
{
int v;
int next;
};
struct classcmp
{
bool operator()(const Template &a,const Template &b) const
{
return a.next < b.next; //按照从小到大自动排序,end()为next最大
}
};
multiset<Template,classcmp>TempNext;
multiset<Template>::iterator it1;
set<int>s;
set<int>::iterator it2;
map<int,int>mp;
int main(int argc, char const *argv[])
{
freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m) != EOF) {
for(int i = 1;i <= n; i++)
scanf("%d",&a[i]);
mp.clear();
for(int i = n;i >= 1; i--) {
if(mp[a[i]]) Next[i] = mp[a[i]];
else Next[i] = n + 1;
mp[a[i]] = i;
}
TempNext.clear();
s.clear();
for(int i = 1;i <= m; i++) {
if(!mp[i]) mp[i] = n + 1;
Template temp;
temp.v = i;
temp.next = mp[i];
s.insert(i);
TempNext.insert(temp);
}
int ans = 0;
for(int i = 1;i <= n; i++) {
it2 = s.find(a[i]);
if(it2 != s.end()) {
Template temp;
temp.v = a[i];
temp.next = i;
TempNext.erase(temp);
temp.next = Next[i];
TempNext.insert(temp);
}
else {
it1 = TempNext.end();
it1--;
ans++;
if(Next[i] < (*it1).next) {
s.erase((*it1).v);
TempNext.erase(it1);
Template temp;
temp.next = Next[i];
temp.v = a[i];
s.insert(a[i]);
TempNext.insert(temp);
}
}
}
printf("%d\n",ans);
}
return 0;
}