一、题目描述
二、算法分析说明与代码编写指导
本题共需要处理 m 个命令,而对 map 的插入、删除、查找的时间复杂度均按 O(logn) 估计 ,所以总的时间复杂度为 O(mlogn) ,按本例数据量,可以暴力解决(当然也快接近时间限制了)。
首先就是用两个映射 f 和 g 建立内存页编号 P 与该页存入内存的时间和访问次数的双向映射。用结构体 pageprop 来保存页面的两个属性(访问次数和存入时间)。f 采用 unordered_map ,能使总时间从 861 ms 降至 446 ms 。g 需要采用有序的 map ,因为 map 是按照 key 排序的,我们需要让访问次数最少的页排在最前面(如果访问次数都最少则将放入内存时间早的页放在最前面)。
建立有序对 p 和 q 方便对 map / unordered_map 进行增删改。
如果内存中找到这个页,直接增加对应的访问计数并将答案 c(只需执行步骤 a 的命令数量)累加即可。
如果没有找到,就要写入内存。用单调增的变量 T 来刻画存入内存的时间,然后将相应的 T 写入对 p ,然后把 p 的两项对调得对 q ,分别插入映射 f 和 g ,就模拟了将该页存入内存的过程。
在写入内存之前,如果内存已满(页面数量超过限制),就需要覆写访问次数最少的页。如果有多个页访问次数最少,就覆盖最早写入内存的页。注意在模拟该过程时,映射 f 和 g 都要进行相应的 erase 操作。
unordered_map 是采用 Hash 来进行存取的,如果哈希写得好,时间复杂度可以按 O(1) 估计。key 为内置类型时,会自动计算好哈希。所以 f 可以直接用 unordered_map ,无需重载(重定义)哈希函数。而对于 g ,因为 pageprop 不是内置类型,所以需要重载排序要用到的 < 运算符。注意当写在结构体内时,二元运算符只需要写一个参数,即右操作数,而 this 指针指向左操作数。
map / unordered_map 的 key 是不允许修改的,如果需要修改 key ,只能把整个对删除,然后将修改了 first 的新有序对重新插入 map / unordered_map 。
三、AC 代码
(446 ms)
#include<cstdio>
#include<algorithm>
#include<map>
#include<unordered_map>
#include<vector>
#pragma warning(disable:4996)
using namespace std;
struct pageprop {
unsign