Atcoder - abc273_e - Notebook(数据结构 + 思维)

abc273_e - Notebook(⇔源地址








tag

⇔数据结构、⇔思维。


题意

给出一本 \(10^9\) 页的笔记本和一个句子,初始时笔记本每一页都是空白的,句子也是空的,现在进行如下操作:

  • 在句子的末尾加上数字 \(x\)
  • 去掉句子末尾的数字(如果句子为空则跳过);
  • 将句子记录到笔记本的第 \(y\) 页;
  • 将笔记本的第 \(z\) 页的内容输出到句子中;

对于每一个操作,输出当前句子末尾的那个数字(如果句子为空则输出 \(-1\) )。


思路

刚开始以为是暴力模拟题,直接写了一个栈来代表句子,写了一个 \(\tt map\) 来代表笔记本,每次都将当前的栈完整的储存到 \(\tt map\) 里面去。结果因为栈开的太大莫名RE,改小了之后又不出所料的超时了,可惜这个时候已经没时间改思路了,遗憾下班。

正解

由于需要记录、读取状态,所以我们需要将全部的操作储存下来,即删除并不代表将其真的删除,那么我们如何实现删除操作呢,联想到指针——可以建立一个类似于链表的结构,使得每一个元素都可以通过 \(pre\) 指针找到其上一级。所以上述的操作转变为:

  • 首先定义节点 \(\{R_{编号}:值\}\) ,其包含两个值:节点编号、节点值。由于节点不删除,所以编号各不相同。

  • 增加:在链表末尾新建一个节点 \(\{R_{len}:x\}\) :其编号为当前链表长度 \(len\) ,其值为 \(x\) 。其为新的末尾节点。随后创建一个 \(pre\) 指针指向其前一级节点。

  • 删除:通过 \(pre\) 指针找到当前末尾节点 \(\{R_{len}:x\}\) 的上一级,其为新的末尾节点;

  • 添加:创建一个 \(\tt map\) 数组,直接记录当前链表末尾节点的节点编号;

  • 读取:直接从 \(\tt map\) 数组中提取节点编号,随后,通过编号我们可以唯一的确定那个节点,并且能够获取其值和 \(pre\) 指针。

这样,我们可以通过一个链表来完整的记录所有的增加和删除;通过一个 \(\tt map\) 数组来完整的储存所有的添加和读取,并且可以通过链表来继续进行增加和删除工作。

后日谈

赛后补题重现赛时的思路,很容易的可以发现:将栈储存到 \(\tt map\) 中这一操作,由于每次需要遍历栈中全部元素,所以极其耗费时间,而且也极其的耗费内存,所以显然是错误的。


AC代码

点击查看代码
int a[N] = {-1}, pre[N], alen, now;
signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	
	int n; cin >> n;
	map<int, int> dic;
	for (int i = 1; i <= n; ++ i) {
		string op; cin >> op;
		char x = op[0];
		if (x == 'A') {
			int x; cin >> x;
			a[++ alen] = x; //当前新增的节点在链表末尾
			pre[alen] = now; //将新增的节点与原节点建立关系
			now = alen;
		}
		else if (x == 'D' && alen > 0) {
			now = pre[now]; //跳回当前节点的上一个
		}
		else if (x == 'S') {
			int x; cin >> x;
			dic[x] = now;
		}
		else if (x == 'L') {
			int x; cin >> x;
			now = dic[x];
		}
		cout << a[now] << " ";
	}
	
	return 0;
}

错误次数:2






文 / WIDA
2022.10.24 成文
首发于WIDA个人博客,仅供学习讨论



posted @ 2022-10-24 10:31  hh2048  阅读(51)  评论(0编辑  收藏  举报