本题解只记录思想。若读者觉得题解思路清晰且想看看代码,可私信联系。
TITLE
整理:
目录:
基础数据结构
练习题:括号匹配(栈)
读取字符串,读到左括号,将其推入栈。读到右括号,栈顶推出一位。如果不能推出,或者栈中最后还剩元素,说明不合法。
练习题:网页跳转(双栈模拟)
访问一个页面,将其加入其中第一个栈中,同时另外一个栈全部清空(无前进的页面)。
返回一个页面,如果第一个栈的大小大于一(前面有访问过网页),那么将原页面置于另外一个栈中,访问栈顶。
前进一个页面,将第二个栈的栈顶置于第一个栈中,然后访问栈顶。
栈体现的思想是后入先出,所以题目的要求也是符合这种模型的。
练习题:n个最小和(优先队列)
先将
{
(
A
i
+
B
1
)
∣
i
∈
[
1
−
n
]
}
\{(A_i+B_1)|i∈[1-n]\}
{(Ai+B1)∣i∈[1−n]}置于优先队列中,后每取出一个数,将
(
A
i
,
B
k
+
1
)
(A_i,B_{k+1})
(Ai,Bk+1)置于优先队列中,进行n次便可。
优先队列体现的思想是优先级高的先出,组合求最小的前n个可以考虑优先队列。重载运算符的时候,要记得权值的比较是反过来的(一半重载<)
练习题:朋友(带权并查集)
用带权并查集维护一下即可。带权并查集可以用来维护一些节点与根节点有关系的树,比如说集合的大小(例如这道题),或者节点到根节点的距离(下面的题目)。关于带权并查集的模板,在计蒜客上有。
队列合并(带权并查集)
在排队过程中,初始时,一人一列。一共有如下两种操作:
合并:令其中的两个队列A,B合并,也就是将队列A排在队列B的后面
查询:询问某个人在其所在队列中排在第几位。
前面一道题说了,使用带权并查集即可。
练习题:找出所有谎言(有意思的权值并查集)
剪刀石头布原则蕴含一个博弈环,实际上我们只需要拿一个点去跟其他点作比较,判断输赢平三种情况即可(确认该点与其他点的输赢关系,其他点的相互关系也能确定下来)。默认该点(下文称根点)的博弈值为0,某节点相对根点为赢,输与平分别为1,2,0,将其加入权值并查集中。当两个节点对应的根点不同时,以两结点关系来连接两个对应根点。两个节点对应根点相同时,判断情况是否矛盾,以此来判断真假。
(权值并查集在重的是节点与根点的关系,与其他节点并无关系。节点合并的时候也是之前权值加上父节点(原先根点)更新后的权值,这个节点就只与新根点有关了)
未整理:
正方形(剪枝dfs)
啊啊啊啊啊啊啊啊啊我tm居然做了一晚上debug对于正n边形木棍匹配的题目,改用先将一条边选出的搜索方式,仔细思考一下,这样的回溯搜索深度很低,完全可以接受。当n-1的合法边被选完后,最后一边也合法,直接跳出。
习题:逃跑(有时间维度的bfs)
这道题涉及到了时间维度,对于这类搜索,最好加一个维度,记为 v i s [ t ] [ x ] [ y ] vis[t][x][y] vis[t][x][y],表示在在t时刻是否能访问这个(x,y)点。在这道题中用此来bfs会方便许多(因为可以预处理子弹的到达情况)。处理的时候比较麻烦,建议用d来划分上界,以免超时。预处理的时候注意多颗子弹在预定时间内打出的轨迹的描述方法(我用的是二重循环,大抵标程也是如此)。
习题:墙壁涂色(思维递推)
考虑
a
n
s
[
n
]
,
a
n
s
[
n
−
1
]
,
a
n
s
[
n
−
2
]
ans[n],ans[n-1],ans[n-2]
ans[n],ans[n−1],ans[n−2]的关系。
当第
n
n
n个填充块颜色与两侧不同时,因为颜色只有三种可选择,所以只有一个颜色可以选。忽略第
n
n
n个色块,这个排列是合法的
f
(
n
−
1
)
f(n-1)
f(n−1),所以方案加
f
(
n
−
1
)
∗
1
f(n-1)*1
f(n−1)∗1
当第n个填充块与两侧相同时,有两种颜色的选择方案,但忽略第n个填充块,这个排列是不合法的。那么就相当于在前n-2种方案中添加两个色块,其中一个色块的颜色跟我们第n个色块相邻的颜色相同,构成我们的方案二。答案便是
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
∗
2
f(n)=f(n-1)+f(n-2)*2
f(n)=f(n−1)+f(n−2)∗2,递推公式有几项,边界值就写几项。