~~~题面~~~

题解:

首先我们要使得Miss的次数尽量少,也就是要尽量保证每个点在被访问的时候,这个点已经存在于Cache中。

那么我们可以得到一个结论:

如果Cache已满,那么我们就从Cache里面取出下一个出现位置最远的那个数(如果不出现了那么令下一个出现位置为inf)

所以用堆维护即可。

我们记录一个Next[i],表示s[i]后面再次遇到s[i]的位置是哪,如果当前的s[i]就是最后一个s[i],那么Next[i] = inf

值得注意的是,遇到相同元素时我们并不需要从堆中删除上一个数然后再塞入当前数,因为这将不会对操作产生影响。而且要强行删除的话要重建整个堆,时间复杂度承受不来。。。

为什么不会有影响?

注意到对于相同元素而言,Next[i]是递增的

即Next[i] < Next[Next[i]] < Next[Next[Next[i]]]

而遇到相同元素就代表遇到了Next[i],所以塞入这个数后,上一个数虽然没有被删除,但被这个数覆盖了,每次取出肯定是优先这个数的

(为什么突然觉得有点不太严谨。。。。那为了保险的话就在取数的时候判断一下就好了)

 // luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 100100
#define inf 10000000
int n, m, tot, cnt, ans;
int s[AC], last[AC], w[AC], Next[AC];
bool z[AC]; struct cmp{
bool operator () (int a, int b)
{
return Next[a] < Next[b];
}
}; priority_queue<int, vector<int>, cmp> q; inline int read()
{
int x = ; char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline bool cmp(int a, int b)
{
return a < b;
} int half(int x)//二分离散化后的编号
{
int l = , r = tot, mid;
while(l < r)
{
mid = (l + r) >> ;
if(w[mid] < x) l = mid + ;
else if(w[mid] > x) r = mid - ;
else if(w[mid] == x) return mid;
}
return l;
} void pre()
{
int x;
n = read(), m = read();
for(R i = ; i <= n; i++) s[i] = w[i] = read();
sort(w + , w + n + , cmp);
for(R i = ; i <= n; i++)
if(w[i] != w[i+]) w[++tot] = w[i];
for(R i = ; i <= n; i++)
{
x = half(s[i]);
if(last[x]) Next[last[x]] = i;//建立一个单向的连接
last[x] = i;//记录上一个出现的x的位置
}
for(R i = ; i <= n; i++)
if(!Next[i]) Next[i] = inf;
}//最后一个的Next为inf(最优先弹出) void work()
{//因为要弹出的是最远的,而之前的相比之后的必然要近一些(同一个数字),而且每次被迫弹出后都必然会塞入一个更远的,
int x, id;//所以之前那些东西放在堆里其实也没关系,不会对答案产生影响
for(int i = ; i <= n; i++)
{
id = half(s[i]);//获取编号
if(z[id])
{
q.push(i);
continue;//如果已经有了,,,那也要赛进去,,,表示替换对应的Next,但不能计入ans
}//因为不删去旧元素并不会造成影响,因此还是可以视作q内没有重复元素的
else if(cnt < m) //如果还没有满
{
++cnt, ++ans;
q.push(i);
z[id] = true;
}
else
{
x = q.top();
x = half(s[x]);//存的是编号
z[x] = false;//已经弹出了
q.pop();
q.push(i);
z[id] = true;
++ans;
}
}
printf("%d\n", ans);
} int main()
{
//freopen("in.in", "r", stdin);
pre();
work();
// fclose(stdin);
return ;
}

[JSOI2010]缓存交换 贪心 & 堆的更多相关文章

  1. B1826 [JSOI2010]缓存交换 贪心+离散化+堆

    这个题仔细一想可以直接贪心做,因为队列里下一个出现的早的一定最优.正确性显然.然后我只拿了50,我直接模拟另一个队列暴力修改最后一个点的nxt值,自然会T.但是其实不用修改,直接插入就行了前面的不影响 ...

  2. 【BZOJ1826】[JSOI2010]缓存交换(贪心)

    [BZOJ1826][JSOI2010]缓存交换(贪心) 题面 BZOJ 洛谷 题解 当缓存不满显然直接放进去,满了之后考虑拿走哪一个.不难发现拿走下一次出现时间最晚的那个一定不会更差. 那么用一个堆 ...

  3. BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

    BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...

  4. 1826: [JSOI2010]缓存交换

    1826: [JSOI2010]缓存交换 https://www.lydsy.com/JudgeOnline/problem.php?id=1826 分析: 简单的贪心,然后调啊调...最近怎么了,码 ...

  5. bzoj1528[POI2005]sam-Toy Cars*&&bzoj1826[JSOI2010]缓存交换

    bzoj1528[POI2005]sam-Toy Cars bzoj1826[JSOI2010]缓存交换 题意: Jasio有n个不同的玩具,它们都被放在了很高的架子上,地板上不会有超过k个玩具.当J ...

  6. BZOJ1826 [JSOI2010]缓存交换 堆 贪心

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1826 题意概括 Cache中有m个储存单元,接下来有n个访问地址,每个地址用一个数字表示.访问每一 ...

  7. [bzoj1826] [JSOI2010]缓存交换

    虽然不知道为什么..但显然,每次扔掉离下次查询最远的内存单元就行了233 用堆来维护贪心...(优先队列大法好 #include<cstdio> #include<iostream& ...

  8. JSOI2010 缓存交换

    题目链接:戳我 考虑一个贪心--就是每次我们都选择队列里面之后最晚加入的元素弹出. 维护一个nxt数组就行了. 特判一下之后不会再加入的元素. 代码如下: #include<iostream&g ...

  9. Luogu P4404 [JSOI2010]缓存交换 优先队列

    细节题?...调了半天.... 可以发现,每一次从缓存中删除的主存一定是下次访问最晚的,可以用优先队列来处理...还有要离散化...还有链表末尾要多建一些点...否则会死的很惨... #include ...

随机推荐

  1. 鸡啄米:C++编程之十三学习之类与对象,类的声明,成员的访问控制

    1. 本次学习鸡啄米课程第13篇,把比较重要的学习记录下来,以敦促自己更好的学习.推荐他们的网址学习:http://www.jizhuomi.com/school/c/97.html 2. 在面向过程 ...

  2. hdu1874畅通工程续(floyd)

    畅通工程续 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  3. appium -- 页面出现弹窗,关闭后,无法识别页面元素

    1. 问题:如图所示:在修改手势密码的过程中,点击了返回按钮后,弹出该弹窗:点击继续设置后,就发现 driver.getPageSource()获取不到页面元素.在找了一圈无用的资料后,没有什么好的处 ...

  4. 接口测试工具postman(五)批量执行测试用例

    1.准备好测试用例及相关数据 2.点击Run按钮 3.选择运行collection或者folder 4.运行完成

  5. Soliworks 2016建模细节总结(1)

    Soliworks 2016建模小细节总结(1) 1.Solidworks 2016三维建模的时候,如果想要在一个视图里面呈现出四个视图(包括三个独立的视图以及三维结构的实体模型图),可以直接按鼠标会 ...

  6. [JSON].toXMLString()

    语法:[JSON].toXMLString() 返回:[String] 说明:将[JSON]实例转换成XML格式结果. 示例: <% jsonString = "{div: 'hell ...

  7. JAVA基础学习之路(四)定义简单java类

    简单java类开发一般原则: 类名称必须有意义,再怎么说,要让人家看的明白吧 类之中所有属性必须使用private封装,并提供setter,getter方法 类之中可以有多个构造方法,但是必须保留有一 ...

  8. Appium ——Android KEYCODE键值:

    Python下语法: driver.keyevent(键值) 电话按键: 键名 描述 键值 KEYCODE_CALL 拨号键 5 KEYCODE_ENDCALL 挂机键 6 KEYCODE_HOME ...

  9. 【机器学习】线性回归python实现

    线性回归原理介绍 线性回归python实现 线性回归sklearn实现 这里使用python实现线性回归,没有使用sklearn等机器学习框架,目的是帮助理解算法的原理. 写了三个例子,分别是单变量的 ...

  10. Python3 Tkinter-Pack

    1.创建 from tkinter import * root=Tk() print(root.pack_slaves()) Label(root,text='pack').pack() print( ...