[JSOI2010] Cache Exchange

Topic link
Luogu (the test example is better)
Niuke (the example is a bit problematic, there is no cache number above 1e6)

Title: [JSOI2010] Cache Exchange

topic background

Thanks to @ACdreamer for contributing data

topic description

In a computer, the CPU can only exchange data directly with the cache. When the required memory unit is not in the Cache, the data needs to be loaded into the Cache from the main memory. At this time, if the Cache capacity is full, one must be deleted from it first.

For example, the current cache capacity is 3, and there are already main storage units numbered 10 and 20.
At this time, the CPU accesses the main memory unit numbered 10, and the cache hits.

Then, the CPU accesses the main memory unit numbered 21, so it only needs to move the main memory unit into the Cache, causing a miss (Cache Miss).

Then, when the CPU accesses the main memory unit numbered 31, a block must be swapped out from the Cache to move the main memory unit numbered 31 into the Cache. Suppose we move out the main memory unit numbered 10.

Then, the CPU accesses the main memory unit numbered 10 again, causing another miss. We see that if other units are deleted during the previous deletion, the absence of this visit can be avoided.

In modern computers, the LRU (least recently used) algorithm is often used for Cache scheduling - but, as can be seen from the previous example, this is not the optimal algorithm.
For an empty Cache with a fixed capacity and several consecutive main memory access requests, Congcong wants to know how to replace the correct main memory unit every time the cache misses, so as to achieve the least number of cache misses.

input format

The first line of the input file contains two integers N and M (1<=M<=N<=100,000), which respectively represent the number of main memory accesses and the capacity of the Cache.

The second line contains positive integers separated by N spaces, and gives the number of each main memory block (not exceeding 1,000,000,000) in the order of access requests.

output format

Output one line, which is the minimum number of Cache misses.

Example #1

Sample Input #1

6 2
1 2 3 1 2 3

Sample output #1

4

hint

Unit 3 is swapped out of the Cache when missing for the 4th time.

the code

#include <bits/stdc++.h>
using namespace std;

/*
实现置换算法
OPT: Optimal,操作系统中最优置换算法,只在理想条件下才可用
warning
就算一个值已经出现在了 Cache 中,相应的信息也要更新!!!(不懂可以debug)
*/
void init() {
    
     ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); }
inline int read() {
    
    
    int x = 0, w = 1; char ch = getchar();
    for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') w = -1;
    for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    return x * w;
}

struct node
{
    
    
    int index, value;
    friend bool operator<(node a, node b)
    {
    
         //从小到大排序采用“>”号;如果要从大到小排序,则采用“<”号
        return a.index < b.index;       //从大到小排序
    }
};
int n, m;
int num=0, ans=0;
const int SIZE = 1e5+10;
// 从当前位置i往后看,下一次i出现的位置
map<int, int> mp;
// 第i个数在不在缓存区内(下标),由于主存块的编号(不超过1,000,000,000)太大,因此采用map
map<int, int> in;
// 存第i个数下一次出现的位置下标
int nexti[SIZE];
int a[SIZE];
// 大根堆,能够将每次置换时把 缓冲区中下个使用时间 离当前最久 的置换出去
priority_queue<node> q;

int main()
{
    
    
    init();
    n = read(); 
    m = read();
    for (int i = 1; i <= n; ++i) a[i] = read();
    for (int i = n; i >= 1; --i)
    {
    
    
        // 未出现过,置为最大值
        if (mp[a[i]] == 0) nexti[i] = SIZE;
        else nexti[i] = mp[a[i]];// 下一次缓存块a[i]出现的位置
        mp[a[i]] = i;// 更新
    }
    mp.clear();// 没用了
    for (int i = 1; i <= n; ++i)
    {
    
    
        // 缺页错误
        if (in[a[i]] == 0)
        {
    
    
            ans++;
            // 缓冲区未满
            if (num < m)
            {
    
    
                num++;
            }
            else
            {
    
    
                // 把缓存区中元素中下一次出现最晚的那个给置换出去
                in[q.top().value] = 0;
                q.pop();
            }
            // 造成缺页的块放入了缓存
            in[a[i]] = 1;
        }
        node t;
        t.index = nexti[i];
        t.value = a[i];
        // 存 新放入的缓存块下一次访问的位置下标
        q.push(t);// 对于已经命中的缓存块而言,之前老旧的信息(上一个等于当前下标)无需删除,新信息的值一定会比老信息大
    }
    cout << ans << endl;
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_33843237/article/details/128050800