HDU 4398 STL + 贪心

13 篇文章 0 订阅

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值