[JSOI2010]缓存交换 贪心 & 堆
题解:
首先我们要使得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]缓存交换 贪心 & 堆的更多相关文章
- B1826 [JSOI2010]缓存交换 贪心+离散化+堆
这个题仔细一想可以直接贪心做,因为队列里下一个出现的早的一定最优.正确性显然.然后我只拿了50,我直接模拟另一个队列暴力修改最后一个点的nxt值,自然会T.但是其实不用修改,直接插入就行了前面的不影响 ...
- 【BZOJ1826】[JSOI2010]缓存交换(贪心)
[BZOJ1826][JSOI2010]缓存交换(贪心) 题面 BZOJ 洛谷 题解 当缓存不满显然直接放进去,满了之后考虑拿走哪一个.不难发现拿走下一次出现时间最晚的那个一定不会更差. 那么用一个堆 ...
- BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心
BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...
- 1826: [JSOI2010]缓存交换
1826: [JSOI2010]缓存交换 https://www.lydsy.com/JudgeOnline/problem.php?id=1826 分析: 简单的贪心,然后调啊调...最近怎么了,码 ...
- bzoj1528[POI2005]sam-Toy Cars*&&bzoj1826[JSOI2010]缓存交换
bzoj1528[POI2005]sam-Toy Cars bzoj1826[JSOI2010]缓存交换 题意: Jasio有n个不同的玩具,它们都被放在了很高的架子上,地板上不会有超过k个玩具.当J ...
- BZOJ1826 [JSOI2010]缓存交换 堆 贪心
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1826 题意概括 Cache中有m个储存单元,接下来有n个访问地址,每个地址用一个数字表示.访问每一 ...
- [bzoj1826] [JSOI2010]缓存交换
虽然不知道为什么..但显然,每次扔掉离下次查询最远的内存单元就行了233 用堆来维护贪心...(优先队列大法好 #include<cstdio> #include<iostream& ...
- JSOI2010 缓存交换
题目链接:戳我 考虑一个贪心--就是每次我们都选择队列里面之后最晚加入的元素弹出. 维护一个nxt数组就行了. 特判一下之后不会再加入的元素. 代码如下: #include<iostream&g ...
- Luogu P4404 [JSOI2010]缓存交换 优先队列
细节题?...调了半天.... 可以发现,每一次从缓存中删除的主存一定是下次访问最晚的,可以用优先队列来处理...还有要离散化...还有链表末尾要多建一些点...否则会死的很惨... #include ...
随机推荐
- jmeter "you cannot switch bacause data cannot be converted to target Tab data,empty data to switch"报错
jmeter "you cannot switch bacause data cannot be converted to target Tab data,empty data to swi ...
- Spring全局变量
压测spring框架的webservice接口,大并发量下响应值与预期值不一致 经查,开发在类中使用全局变量导致: springmvc核心控制器DispatcherServlet 默认为每个contr ...
- lesson 24 A skeleton in the cupboard
lesson 24 A skeleton in the cupboard conceal sth from sb 对某人隐藏某事 He conceals his girlfriend from his ...
- lintcode: Missing String
Missing String 描述: Given two strings, you have to find the missing string. Have you met this questi ...
- 407. Plus One【LintCode java】
Description Given a non-negative number represented as an array of digits, plus one to the number. T ...
- node事件循环
Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.j ...
- 1 wait notify
wait/notify: wait()使线程停止,notify使wait状态的线程继续执行. wait()是Object类的方法,该方法用来将线程置入“预执行队列”,并在wait()方法处停止执行,直 ...
- vivado使用感想
寒假学了一学期vivado也没有学出什么名堂:为了调试龙芯的五级流水CPU,今天肝了一下午结果还把vivado给摸清楚了,果然是以目标为导向最能出成绩. vivado开发硬件的流程 写代码 模拟仿真s ...
- Servlet过滤器介绍之原理分析
zhangjunhd 的BLOG 写留言去学院学习发消息 加友情链接进家园 加好友 博客统计信息 51CTO博客之星 用户名:zhangjunhd 文章数:110 评论数:858 访问量:19 ...
- C Program基础-宏定义
写好c语言,漂亮的宏定义是非常重要的,我们在阅读别人工程时,往往能看到大量的宏定义,宏定义可以增加代码的可读性,也能增加代码的可移植性,一个好的宏定义甚至是一件艺术品.今天我们就来看看宏定义的方方面面 ...