AtCoder Beginner Contest 268 Solution

更好的阅读体验戳此进入

题面链接

题面 Luogu 链接

ab 不说了

[ABC268C] Chinese Restaurant

题面

N 个人从 0 开始编号, 按逆时针顺序间隔均匀地坐在转盘周围。 在开始时, 第 pi 盘菜在第 i 个人的前面。

现在, 你可以进行以下操作 0 次或多次。

当你结束操作后,如果第 i 盘菜在第 (i1)modN 个人、第 i 个人或第 (i+1)modN 个人面前,第 i 个人就会感到高兴。

请求出你最多能使多少人感到高兴。

Solution

不难想到单向记录 ipi 的距离,然后每次枚举挨着的三个 dis 求和即为本次的答案。取最大值即可。

Code

[ABC268D] Unique Username

题面

给定 n 各字符串,另外给定 m 个字符串。你需要对 n 个字符串进行排列,并在每相邻两个字符串中间插入至少一个下划线,并且最终字符串与给定的 m 个字符串均不同。输出任意一个长度在 [3,16] 的方案。

Solution

第一眼没什么想法,看了一眼数据范围才反应过来这似乎就是个暴力,我们尝试分析一下:

n 个字符串总长度和为 s,我们还要至少插入 n1 个下划线,那么剩下的可能长度就只有 16s(n1)=17ns,同时显然 sn。对于剩下的长度不难发现可以认为其是将下划线可空地放入 n1 个不同盒子里,显然这就是 17ns 个可空的不同球盒问题。关于球盒问题可以去看我的 Blog:浅析排列组合、斯特林数、贝尔数、二项式定理与推论及其反演、子集反演、广义容斥。再加上枚举全排列的 n!,最终的复杂度大约是:

O(n!i=017ns(i1+n1)!(n2)!(i1+n1(n2))!)

化简一下:

O(n!i=017ns(i+n2)!(n2)!i!)

这一大坨东西我不知道我是否分析错了,不过大概也八九不离十,总之这个东西我们随便带入几个 n 算一下,或者感性理解一下发现显然是远小于 1e8 的,所以暴力即可通过。

做法的话先通过调用 n!next_permutation() 函数枚举全排列,此时还会多一个 O(n) 的常数,不过区别不大。

然后每次跑一遍深搜,用 string 的本质是 basic_string,且 basic_string 支持 ++= 等的特性,即可十分便捷地实现一般的深搜思路,注意每两个之间至少插入一个下划线,且注意需要限制最多额外添加 17ns 个下划线,否则复杂度是不正确的。

Code

[ABC268E] Chinese Restaurant (Three-Star Version)

题面

n 个人进行圆排列,即围坐在圆桌周围,位置编号依次为 [0,n1],给定序列 Pn 表示第 i 个人喜欢的菜品在 Pi 处,Pi[0,n1] 且各不相同。定义每个人的沮丧值为其位置与 Pi 的距离。你可以任意旋转圆桌,以最小化所有人的沮丧值之和,求最小值。

Solution

可以说是一道思路较为简单但细节巨多非常难调的题,到处各种加加减减与分类讨论,这么一道水题最后我写了一个半点。

首先我们可以想到,我们认为初始状态为 ii1,然后认为初始状态之后转的格数为 x 轴,对于一个特定的人的沮丧值为 y 轴,不难想到图像应为至多三段斜率为 11 的线段组成,同时若点数为奇数,那么在距离 Pi n2n2 的对应位置的值是相同的,也就是此时斜率应为 0,但有且仅有这么一段。对于答案我们只需要将每个人的情况都合并起来求一下最小值即可,考虑如何维护。

于是我们直接考虑 y 轴的值,对于一个人的变化量显然是类似 1,1,1,1,1,1,0,1, 等,这个东西等于是做了个差分。不难发现这东西如果用线段树维护区间修改,那么最终复杂度应为 O(nlogn) 的,不过我不想写线段树,于是考虑另一种写法,不难发现这东西是很多个区间修改,所以可以对差分数组再次做差分,即二阶差分,此时我们只需要在转折点处做一下修改即可,这样最后做两次前缀和求个最大值即可。

不难发现这东西思路显然看起来很简单,但是当实现的时候就会发现阴间的地方在哪了。首先我们发现有四种情况,即 ipi 的偏序关系,和 (ipi)modn(pii)modn 的偏序关系。但是经过讨论我们会发现,前者的偏序关系是无意义的,因为我们求距离时可以直接转正,即 dis=(ipi+n)modn,所以此时优化情况为两种。

具体情况可以自己画一下然后看看代码,还是比较显然的,只是细节太多了。

Code

[ABC268F] Best Concatenation

题面

给定 n 个由 X 和数字构成的字符串,你需要对其进行排列并拼接成新的字符串 T 以最大化其分数。定义其分数为对于字符串中每一个数字,使数字对应的数值乘上其之前 X 的数量,并求和。输出分数最大值。

Solution

首先一个显然的结论即为对于题目定义的分数,同一字符串内部的 X 对其数字的贡献,与字符串在排列中的顺序无关。

于是我们考虑其它字符串的 X 对字符串数字的贡献,我们考虑字符串 Si,Sj,令 cnti 表示字符串 iX 的数目,令 sumi 表示字符串 i 中所有数字数值之和。显然若 SiSj 之前,ji 无贡献,ij 的贡献为 cnti×sumj。反之则为 cntj×sumi

则不难想到若我们要将 Si 放在 Sj 之前,那么一定有这样的贡献更大一些,即 cnti×sumj>cntj×sumi

所以我们直接考虑对字符串进行排序,比较规则则按照刚才的式子跑一下即可。

同时我们也可以从意义上感性理解,显然只有前面的 X 对后面的数字产生贡献,所以我们将 X 更多数字更少的放在前面,则 cntisumi 可以作为一个类似估价函数的作用进行排序,转换一下即我们刚才证明的上式。

同时对于此贪心的证明,考虑若满足偏序关系 S1,S2S2,S3,那么一定也有 cnt1×sum3>cnt3×sum1,所以也有偏序关系 S1,S3,也就是 S1,S2,S3,扩展到整个序列依然满足。

存在双倍经验 LG-P1080 [NOIP2012 提高组] 国王游戏

Code

[ABC268G] Random Student ID

题面

给定 n 名学生的名字 Si,保证不重复。现在随机一个 az 的排列作为字典序的偏序关系,求每个同学排名的期望,对 998244353 取模。

Solution

这一题可以说确实很高妙,确实没想到还可以这么处理。

第一眼以为是一些类似 期望DP 的东西,然后想了半天也没想到什么复杂度正确的做法,实际上这道题是从期望的意义去找性质。

首先我们考虑对于一个串 S 的期望排名,若存在串 S 的前缀串 T,那么显然串 T 无论字典序的偏序关系如何都会在 S 之前,所以一定会贡献 1

而若存在 ST 的前缀,那么显然 TS 之后,则贡献一定为 0

对于其它的情况,显然会由 LCP 之后的第一个不同的字符决定,而对于这种显然在所有字典序关系中两者的偏序关系的概率是相同的,所以此时的贡献为 12。那么对于字符串 S,若其前缀串有 x 个,满足有 S 前缀的串有 y 个,那么答案即为:

x×1+y×0+(nxy1)×12+1

然后对于求前缀,显然可以通过 Trie树 解决,同时也可以考虑一些更简单的方法:

开一个 unordered_set,往里面丢每个串的哈希值,然后对于每个串的每个前缀的哈希在里面查一下然后记录即可,最终复杂度 O(|Si|)

Code

[ABC268Ex] Taboo

题面

给定仅有英文小写字母的字符串 S,可以对其进行若干次操作,每次将 S 中某个字符替换为 *。给定 n 个仅有英文小写字母的模式串,要求进行操作使得 S 中不存在任意子串与模式串相同。最小化操作次数,输出最小值。

Solution

提供一个理论复杂度正确但因常数以及哈希原因无法通过的做法,同时略提正解。

首先我们不难想到,我们若对 S 匹配模式串 T,显然若匹配到了,那么我们直接将匹配到的部分的最后一位改为 * 即可,贪心正确性显然,若改前面的可能会存在后面再次匹配使得不优。

然后对于所有匹配,我们也不难想到处理的顺序可以是先处理长度较小的串,然后再处理较长的。此处的贪心正确性仍显然,因为短的串处理时一定会尽量地破坏长的串,总之感性理解一下。

所以就不难想到一个做法,开一个 map < int, unordered_set < unsigned long long > >,对每个长度的串映射一个 set 存储所有该长度的模式串的哈希值,然后按序跑一遍,通过维护哈希来 O(n) 跑一遍并匹配与替换。

分析一下这个的复杂度,显然每种长度都会跑一遍 O(n),那么卡此做法的构造应使长度为等差数列,而等差数列求和是 O(n2) 级别的,所以最多的长度种类为 O(Ti),也就是说最终复杂度是根号级别的。不过此时我们会发现这俩都是 5e5 级别的,似乎过不了?但是再看一眼时限 4s,又似乎刚好能过。

不过实现之后会发现,部分测试点 WA,部分 TLE,TLE 的部分大概用了 10s,若改为 unsigned int 时间可以到 7s,但是同时也存在问题即哈希碰撞。我们自然可可以通过手写挂链或双模数等以使得满足正确性,但是时间上理性分析一下,等差数列实际是 n22 的,所以此时还有个 2 倍常数,所以时间两倍之后寄掉也就很合理了。如果卡的不够死的话理论上还是可以改过的,但是也只是理论上,有兴趣可以尝试一下。

这里浅提一下正解,考虑刚才提到的贪心策略之后对于将所有模式串匹配掉直接写一个 AC自动机 即可,具体实现可以考虑如果一个节点的 fail 存在模式串那么该节点也认为是可以匹配的,也就是按照之前的贪心,优先去匹配更短的串。

Code

理论复杂度正确但无法通过的代码

正解代码

UPD

update-2023_01_18 初稿