NC20185 [JSOI2010]缓存交换

图片说明
这是一道堆的题,堆的题常与贪心有关,此题也是。
借鉴别人的博客 + 别人的代码给整明白了,于是乎自己写篇博客再理理思路
首先这个题肯定是要在下标上做文章,因为要判断当前数是否在缓存区内,我们可以用一个bool数组,而这个数组肯定存第i个数在不在缓存区内,所以bool[i]的这个i就是指第i个数,不能指i这个数在不在缓存区内,因为最大值1e9,开不了那么大的数组,而找到第i个数下一次出现的数组nexti同样。

思路:
1.大体思路:
我们把前m个数放到缓存区后,再碰到不在缓存区里的数时,我们需要删除一个原来在缓存区的数,然后把这个数加到缓存区内,首先问题在于删除那个数,我首先想到删除后面出现少的那个数,但这不对,反例如下:
1000 3
12 15 16 14 12 15 14 12 15 后面的数全是16
对于这个样例,如果对于14这个数,用上面的思路一定不删16,而实际上删16最划算,因为你不管删12还是15,在后面的几个数中你都要频繁的删数,而删16的话,紧跟着后面的这几个数不需要删除,后面的一坨16也只需要处理一次即可。
正确的贪心是,把缓存区中元素中下一次出现最晚的那个给删除了,所以我们需要一个数组来存第i个数的下一次出现在哪里,要一直找最晚的我们需要一个堆等等
2.需要维护什么?代码具体怎么写?
根据上面的分析我们需要维护这么几个容器:
(1).bool型数组boo[i],表示第i个数在不在缓存区内
(2).int型数组nexti[i] (这个很离谱,我定义为next时牛客编译不过,自己编译器过了,改了个名好了),存第i个数下一次出现的位置
(3).堆q
(4).map<int,int> mp这个一开始妹李姐。
这个map是基于当前位置i,从n到1找ar[i]最后一次出现的位置(注意这个顺序n ~ 1),即基于当前位置向后找第一次出现ar[i]的位置(有点绕,感觉又是把5星难度东西说成了8星)
需要维护的变量:
(1).num 当前缓存区内元素个数
(2).ans 答案
代码提纲:
看别人代码后自己整理思路写了个提纲,要不然自己写的时候还有点脑子不够用想看别人的代码
1.维护nexti数组
我们需要知道元素ar[i],即第i个数下一次出现在哪里。我们需要从n到1遍历,原因是那个map。
判断ar[i]这个数是不是最后一次出现,是最后一次出现则,nexti[i]中存一个很大的数
不是则存下一次出现的位置mp[ar[i]] 当时不李姐为什么mp[ar[i]]就是下一次出现的位置)
最后更新mp[ar[i]]的值
2.从1~n开始遍历

判断第i个数在不在缓存区内
    不在(ans++)
        num<k,
        需要做三件事,1.num++。2.第i个数下次出现的位置置为1。3.把下一次出现的位置放到堆里
        否则,
        四件事,1.取堆顶并pop。2.改变boo数组。3.同上面的2。4.同上面的3
    在
        更新boo,更新堆(不需要取出i,因为i永远不可能在堆顶了)。

AC代码:

#include <bits/stdc++.h>

using namespace std;

int n, m;
map<int,int> mp;
bool boo[100050];
int nexti[100050];
int ar[100050];
priority_queue<int> q;
int num, ans;

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]);
    for(int i = n; i > 0; --i)
    {
        if(mp[ar[i]] == 0)  nexti[i] = 100050;
        else    nexti[i] = mp[ar[i]];
        mp[ar[i]] = i;
    }
    for(int i = 1; i <= n; ++i)
    {
        if(boo[i] == 0)
        {
            ans++;
            if(num < m)
            {
                num++;
                boo[nexti[i]] = 1;
                q.push(nexti[i]);
            }
            else
            {
                boo[q.top()] = 0;
                q.pop();
                boo[nexti[i]] = 1;
                q.push(nexti[i]);
            }
        }
        else
        {
            boo[nexti[i]] = 1;
            q.push(nexti[i]);
        }
    }
    printf("%d\n", ans);
    return 0;
}