用队列按进入顺序模拟容量 M 的内存、布尔数组判命中:未命中计数入队,满员淘汰队首,O(N) 求出查词典次数。
OJ: roj
题目 ID: 3582
难度:普及-
标签:模拟队列python
创建: 2026-10-02 09:04
更新: 2026-10-06 14:35
题目描述
翻译软件逐词翻译文章:内存中有该单词就直接使用;没有就查一次外存词典,并把单词放入内存。内存有
输入:第一行两个正整数 1 2 1 5 4 4 1,输出 5。
思路
内存的变化只有"尾部追加新词、头部淘汰最老词",命中不刷新顺序,所以用队列按进入顺序存单词,命中判断用布尔数组 in_memory[] 做
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 09:04
# update_at: 2026-10-02 09:04
import sys
from collections import deque
def count_lookups(capacity: int, words: list[int]) -> int:
"""FIFO 内存模拟:统计需要去外存查词典(未命中)的次数。
deque 按进入顺序存词,集合 O(1) 判在不在;内存满时淘汰队首,
即题面要求的"清空最早进入内存的那个单词"。
"""
cache: deque[int] = deque() # 进入内存的先后顺序
present: set[int] = set() # 配合 deque 做 O(1) 命中判断
lookups = 0
for word in words:
if word in present:
continue # 内存里有,不查词典
lookups += 1 # 没有,去外存查一次
if capacity == 0: # M=0 时内存存不下任何词
continue
if len(cache) == capacity: # 内存满了
oldest = cache.popleft() # 淘汰最早进入的词
present.discard(oldest)
cache.append(word)
present.add(word)
return lookups
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
capacity = next(data) # M:内存单元数
length = next(data) # N:文章单词数
words = [next(data) for _ in range(length)]
print(count_lookups(capacity, words))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 14:34
* update_at: 2026-10-06 14:34
*/
#include <cstdio>
typedef long long ll;
const int MAXV = 1005; // 单词大小不超过 1000
int m, n;
int word; // 当前读入的单词
int q[MAXV]; // 内存队列:q[head] 是最早进入的单词,q[tail-1] 是最新的
int head, tail; // 队列的队首和队尾(左闭右开)
bool in_memory[MAXV]; // in_memory[w] 表示单词 w 当前是否在内存里
ll ans; // 查词典的总次数
int main() {
scanf("%d %d", &m, &n);
// M 可以为 0:此时内存永远为空,每个词都要查词典
for (int i = 1; i <= n; i++) {
scanf("%d", &word);
if (in_memory[word])
continue; // 内存里已有,命中,不查词典
ans++; // 未命中,查一次词典
if (m > 0) { // M=0 时存不下任何词,只计数
if (tail - head == m) { // 内存已满
in_memory[q[head]] = false; // 淘汰最早进入的单词
head++;
}
q[tail] = word; // 新单词进入内存
tail++;
in_memory[word] = true;
}
}
printf("%lld\n", ans);
return 0;
}