做题笔记 指针(洛谷P1540 机器翻译 NOIP2010提高组)

题目传送门 P1540 机器翻译

在这里插入图片描述

思路分析

我们仔细看题目这一段

假设内存中有M个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过M-1,软件会将新单词存入一个未使用的内存单元;若内存中已存入M个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。

清空最早那个单词,存放新单词,我们用样例模拟一下就是这样
在这里插入图片描述
所以这题我们可以用指针
用指针l指最左边,r指最右边,存入一个单词后r++,如果r>m,那么左指针l所指的数清零,l++
这里开两个数组作内存,第一个数组a是类似一个桶,初始值为零,如果对应下标的数字存入b数组(b数组是内存)里,该数置为1,所以搜索输入的x时只需要判断a[x]即可

我们来看代码

#include<iostream>
using namespace std;
int a[1005],b[1005];    //a,b数组作用已经说过
int n,m,x;
int main(){
	cin>>m>>n;
	int l=0,r=0;    //指针初始化,这里很巧妙,至于为什么继续看下面的语句
### NOIP 2010 提高 P1540 机器翻译 题解与代码实现 NOIP 2010 提高 P1540 机器翻译是一道经典的编程题,主要考察队列数据结构的应用以及对时间复杂度的优化。以下是对该题的详细解析及代码实现。 #### 问题描述 给定一个内存大小 \( m \) \( n \)单词,每次输入一个单词时需要判断该单词是否已经在内存中存在。如果不存在,则将其加入内存,并记录查找次数;如果内存已满,则移除最早进入内存单词以腾出空间。 #### 解决思路 为了高效解决此问题,可以使用以下方法: - **布尔数**:用于标记某个单词是否已经存在于内存中。 - **双端队列(Deque)**:模拟内存操作,支持在队尾插入单词从队首移除最早进入的单词。 通过上述方法,可以在 \( O(1) \) 的时间内完成单词的查找与插入操作[^1]。 #### C++ 实现代码 以下是基于双端队列的完整实现: ```cpp #include <bits/stdc++.h> using namespace std; deque<int> dq; // 定双端队列,存储当前内存中的单词 bool vis[1010] = {false}; // 布尔数,标记单词是否已在内存中 int m, n, a, dep = 0, cnt = 0; // dep 记录内存单词数量,cnt 记录查找次数 int main() { cin >> m >> n; // 输入内存大小单词数量 for (int i = 1; i <= n; i++) { cin >> a; // 输入当前单词 if (!vis[a]) { // 如果单词不在内存中 vis[a] = true; // 标记为已存在 cnt++; // 查找次数加一 if (dep == m) { // 如果内存已满 vis[dq[0]] = false; // 将最早进入的单词标记为不存在 dq.pop_front(); // 移除最早进入的单词 } dq.push_back(a); // 在队尾插入当前单词 dep = min(dep + 1, m); // 更内存单词数量 } } cout << cnt; // 输出总查找次数 return 0; } ``` #### 关键点分析 1. **布尔数的作用**:通过 `vis` 数快速判断某个单词是否已在内存中,避免重复插入[^1]。 2. **双端队列的操作**:利用 `push_back` `pop_front` 模拟内存的先进先出特性[^1]。 3. **时间复杂度优化**:通过空间换时间的方式,将每次查找的时间复杂度降低至 \( O(1) \)[^4]。 #### 其他实现方式 除了使用双端队列,还可以通过数模拟队列的方式来实现。以下是一个基于数的实现示例: ```cpp #include <iostream> using namespace std; int main() { int n, m, k, count = 0, j = 0, l = 0; cin >> n >> m; // 输入内存大小单词数量 int a[1001] = {0}, b[1001]; // a 数标记单词是否存在,b 数模拟内存 for (int i = 0; i < m; i++) { cin >> k; // 输入当前单词 if (a[k] == 0) { // 如果单词不在内存中 count++; // 查找次数加一 j++; // 内存指针后移 b[j] = k; // 将单词加入内存 a[k] = 1; // 标记为已存在 if (j > n) { // 如果内存已满 l++; // 移动起始位置指针 a[b[l]] = 0; // 将最早进入的单词标记为不存在 } } } cout << count; // 输出总查找次数 return 0; } ``` 此实现方式同样满足题目要求,但使用了更简单的数结构[^3]。 #### 注意事项 - 确保输入数据范围符合题目要求,避免因数越界导致错误。 - 在实际应用中,可根据具体需求选择合适的数据结构,如双端队列或数模拟队列[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值