刷题记录:Codeforces Round #731 (Div. 3)
Codeforces Round #731 (Div. 3)
20210803。网址:https://codeforces.com/contest/1547。
感觉这次犯的低级错误有亿点多……
A
一个大水题。
B
给我一个字符串,让我判断它是否alphabetical。一个alphabetical字符串可以这样生成:首先放一个a,然后在左边/右边放一个b,然后再在新字符串的左边/右边放一个c……也就是,新串=最新字母.append(旧串),或新串=旧串.append(最新字母)。
所以我们维护一个left一个right,left和right的初值为0和n-1,不断用这两个指针去比较边缘处的字母是否为【当时所加入的最新字母】,进行剥洋葱般的操作。
C
两个人打算coauthor一篇paper,每一时刻只能有一个人在操作,操作只能是增加一行或修改【已存在】的一行。两个人都有自己的操作序列,只能按照这个顺序来进行操作。给出paper原始行数和两个人的操作序列,问他们能否合作成功,如果成功就给出一个可行的总操作序列。
关于两个人的操作序列:若甲的操作序列是12,乙的操作序列是45,那么可以1245、4512、1425、4152、1452、4125,也就是1必须在2之前,4必须在5之前。
我的想法是简单的贪心:只要不出现【修改不存在的一行】这种情况,那么就可以成功。保险起见,当然希望修改前的行数越多越好。所以在试图生成总操作序列时,如果还可以增加一行,那就继续增加。如果两个人都只能做修改操作了,那就【先判断此时有没有可以做的修改操作】,如果有的话【接着判断那个人能否一鼓作气再增加几行】。
D
一个growing的数列是这样的:把所有数用二进制表示,\(a_i\)中为1的那些位在\(a_{i+1}\)中也为1,也就是\(a_i\&a_{i+1}=a_i\)。两个co-growing的数列满足:它们每一个数【按位异或】后得到的新数列是growing的。
给我们一个数列,让我们找一个【按字典序比较】最小的数列,使得这两个数列co-growing。
异或是这样一种操作:输入1就改变一位,输入0就不改变。首先,对于\(a_i\)中为0 \(a_{i+1}\)中为1的一位,用异或将\(a_i\)中的该位变成1,是没有必要的。然后,对于\(a_i\)中为1 \(a_{i+1}\)中为0的一位,与其用异或将\(a_i\)中的该位变成0,不如用异或将\(a_{i+1}\)中的该位变成1,因为我们想要【按字典序】最小的序列,靠前的数越小越好。这样,\(a_0\)完全不改变,\(a_1\)改变去贴合\(a_0\),\(a_2\)改变去贴合\(a_1\),……,就可以得到我们想要的数列了。
E
有一个长度为n(就是有n个位置)的走廊,每一个位置可以放一个空调或不放。某一个位置的温度为:【某一空调温度+空调与该位置距离】的最小值。(可以看出,题目认为空调是制冷而非制热的。)
现在给出空调的分布,让我们求每一位置的温度。
我的想法是简单的扫描:先考虑冷风从左往右传的情况,从左往右扫描一遍,维护一个【等效空调】。对于没有空调的位置,就用【等效空调+冷风从左往右传】算温度;对于有空调的位置,判断【该空调】和【等效空调传到此位置的冷风】哪一个更冷,更新等效空调。然后考虑冷风从右往左传的情况,再从右往左扫一遍。对两个结果取min,就是每个位置的温度了。
编程细节:为了好处理,可以在0和n+1两个位置放上无穷热的空调。
F
给我们一个全是正整数的数列,问操作多少次能使数列的每一个数都一样。
一次操作:每个数=它(\(a_i\))与它右边的那个数(\(a_{i+1}\))的gcd。\(a_{n-1}\)去和\(a_0\)取gcd,即\(a_{n-1}=gcd(a_{n-1},a_0)\)。
做法:首先求这个数列所有数的gcd,然后所有数都除它。这样,多次操作后【所有数都一样】就是【所有数都为1】了。然后打一个素数表,对每个素数进行这样的操作:对数列中每个数判断该素数是否为其因子,考察【最长的、每个数都是该素数倍数的连续数列】有多长。我们做【该长度】次操作,就可以把这个素数因子消除了。所以,最后的答案是:对每个素数求【长度】,然后取max。
编程细节:数列中的数最大有\(10^6\)这么大,因此我们可以打一个只到\(10^3\)的素数表。然后对于判断过的素数,把数列中的每一个数都不停地除这个素数,直到这个素数彻底不是任何一个数的因子。这样,考虑完素数表中的素数,如果数列里还有很大很丑陋的数,就可以认为这是一个大素数,我们要对大素数再求一次【长度】。此处我犯了一堆错误,并且不是第一次犯类似错误了……
G
给我们一个有向图,可能会有环和自环,但没有重边。对于每一个节点,判断【节点1没有路径到达它(0)/有1条路径到达它(1)/有多条(但有限)路径到达它(2)/有无数条路径到达它(-1)】。如果节点1没有通向它自己的自环,那么就是1,否则-1。
做法:dfs的思想。
- 从1出发开始dfs,搜过的节点标记成黑色,正在搜(正在遍历它的分支)的节点标记成灰色,未搜过的节点标记成白色。
- dfs的过程是这样的:对于一个白色的节点,遍历它邻接的所有节点:如果该节点是白色的,就继续dfs该节点。
- 如果发现我邻接的节点是灰色的,正是从它那里递归调用才会遍历到我,而我现在又试图递归搜索它,这证明我们都是-1。
- 如果发现我邻接的节点是黑色的,证明已经有人先遍历过它了,它可以通过别的路径到达,这样的节点应该是2。如果它不是-1,它就是2。
- 因此,我们先进行dfs,同时维护-1集合和2集合。把所有能dfs到的节点标为1,遇到灰色情况就把节点加入-1集合,遇到黑色情况就把节点加入2集合。然后,对于-1集合中的每个节点进行搜索,它们能到达的所有节点都应该是-1。对于2集合中的所有节点进行搜索,它们及它们能到达的【不是-1的】所有节点都应该是2。
编程细节:加入2集合的节点也可能是-1,比如说这样的情况: