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个人博客,仅供学习讨论
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号