LRU
题意 :
(吐槽计算机组成原理)计算机内存分块构成,由1 − n编号。现在要求求缓存的块数,使得对于给定的长度为n 的请求序列,少k 次命中缓存。其中,在命中缓存时有三种情况:
1.缓存中存在当前请求编号的块,此时命中该编号的缓存;
2.未命中缓存,缓存未满,当前块写入缓存;
3.未命中缓存,缓存已满,替换缓存中时间最久的块;
思路 :
二分一个长度并进行检验,检验时用一个s e t 维护Cache中的块编号,并按照请求序列的先后顺序进行排序,用一个m a p维护映射元素上一次的出现位置。
对于命中缓存的情况,先擦除上次的数据,再保存本次的编号;
对于缓存已满的情况,则擦除set中的第一个元素(历史最久远的块),然后插入新块;
缓存未满,直接插入新块。
有一个技巧,在插入元素时不要使用insert,而是使用emplace方法,避免插入时多余的一次构造和析构,可以提升程序效率。
AC代码 :
#include <iostream>
#include <unordered_map>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <set>
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int long long
using namespace std;
const int N = 1e5 + 10;
int a[N];
struct node {
int idx, val;
bool operator<(const node& a) const { return idx < a.idx; }
};
bool check(int x, int n, int k){
set<node> se;
unordered_map<int, int> mp;
int cnt = 0;
for (int i = 1; i <= n; ++i) {
if (mp.count(a[i])) {
++cnt;
se.erase({mp[a[i]], a[i]});
se.insert({i, a[i]});
mp[a[i]] = i;
continue;
}
if (se.size() == x) {
node top = *se.begin();
se.erase(se.begin());
mp.erase(top.val);
}
mp[a[i]] = i;
se.emplace(node{i, a[i]});
}
return cnt >= k;
}
signed main(){
IOS;
int n, k; cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
int l = 1, r = n + 1, ans = -1;
while(l <= r){
int mid = l + r >> 1;
if(check(mid, n, k)) r = mid - 1, ans = mid;
else l = mid + 1;
}
if(ans < 0) puts("cbddl");
else printf("%lld\n", ans);
return 0;
}