CCF-CSP 36-3 缓存模拟(cache)【C++】

题目

题目链接:TUOJhttps://sim.csp.thusaac.com/contest/36/problem/2

参考:CCF-CSP第36次认证第三题------缓存模拟(满分题解)_ccfcsp缓存模拟-CSDN博客

思路

1. 数据结构设计

核心存储结构

  • cache[NN] :每个组(共 N 组)维护一个 set<int>,记录该组当前缓存了哪些内存块

  • lru[NN] :每个组维护一个按访问时间排序的 set<pair<时间戳, 内存块>>,用于实现 LRU 替换策略

辅助映射表

  • tim[pos] :记录每个内存块 pos 的最后访问时间戳

  • change[pos]:脏位标记,记录内存块是否被修改过(写回时需要写回内存)


2. 关键算法逻辑

地址映射

给定内存块地址 pos:

  • 组索引 :id = (pos / n) % N

  • 每组可容纳 n 个内存块(n 路组相联)

缓存访问流程

  1. 判断命中:

    • 若 cache[id] 中存在 pos → 缓存命中

    • 若未命中 → 需要加载或替换

  2. 未命中处理:

    • 如果该组已满(cache[id].size() == n),调用 pop(id) 执行 LRU 替换:

      • 弹出 lru[id] 中时间戳最小的块(最久未使用)

      • 若该块被修改过(change[pos] == 1),则输出 "1 pos" 表示写回内存,并清除脏位

      • 从 cache[id] 中移除该块

    • 加载新块:输出 "0 pos" 表示从内存读取,并将其加入 cache[id]

  3. 更新访问信息:

    • 更新该块的时间戳 tim[pos] = nowtime

    • 将 (tim[pos], pos) 插入 lru[id](若已在缓存中,需先删除旧记录再插入)


3. 操作类型

  • o == 1 :写操作,标记 change[pos] = 1(脏位)

  • 默认或 o == 0:读操作(代码中未显式判断 o==0,但 o==1 之外的均视为读)


4. 输出格式

  • 0 pos :表示从内存加载块 pos 到缓存

  • 1 pos :表示将脏块 pos 写回内存

代码

【对上面的代码按照自己的习惯进行了改写,但是逻辑基本一致】

可以看到代码量并不大,可惜之前几次没好好珍惜考试的机会,拿到200分就撤了

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define pii pair<int,int>

const int NN=1e5+5;
int n,N,q, nowtime; //时间戳 

map<int,int>tim; //时间戳  
map<int,int>change; //被修改过(替换的话要先写入内存) 
set<int>cache[NN];  //NN:组数 //这种i组取set,不用map反而比较方便,用数组 O(1) 
set<pii>lru[NN]; //(时间戳 ,当前内存块号pos) 

void pop(int id)
{
	auto it=lru[id].begin();
	int pos=it->second;
	if(change[pos]) 
	{
		cout<<1<<" "<<pos<<endl;
		change[pos]=0; 
	}
	cache[id].erase(pos); //WARN:脏位设为0
	lru[id].erase(it); //warn:lru[id] not lru
}

void insert(int id,int pos)
{
	cout<<0<<" "<<pos<<endl;
	cache[id].insert(pos);
}

void solve()
{
	cin>>n>>N>>q;
	while(q--)
	{	
		nowtime++; //最近的查询最大,时间戳越大  
		int o,pos; cin>>o>>pos;
		if(o==1) change[pos]=1; 
		int id=(pos/n)%N; //组的id 
		if(cache[id].count(pos)) //在缓存区 
			lru[id].erase(lru[id].find({tim[pos],pos}));
		else // 不在缓存区 
		{
			if(cache[id].size()==n) pop(id);
			insert(id,pos); 
		}
		//查询完之后更新访问时间 
		tim[pos]=nowtime;
		lru[id].insert({tim[pos], pos});
	}
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	solve();
	return 0;
}
相关推荐
h39742 小时前
DirectShow过滤器开发-视频源过滤器
c++·windows·音视频·directshow
夏幻灵3 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码3 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
西飘客4 小时前
vs 怎么根据dll 生成lib文件
c++·qt
bkspiderx5 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
程序员老陆5 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光5 小时前
C语言入门,深入理解指针(3)
c语言·开发语言
信奥卷王5 小时前
[GESP202609 六级] 分树规划
算法
夏幻灵5 小时前
LeetCode 21:合并两个有序链表——双指针与哑节点详解
算法·leetcode·链表
码云数智-园园5 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言