Codeforces 666C Codewords

题意

已知一个字符串 s ,有 m 个询问需要你回答。

对于每个询问,有两种可能性:

  • 1型:给你另外一个字符串 s' ,然后令s = s'。(即用新串更新当前的s
  • 2型: 给你一个整数n,你要回答:可以构造多少种不同的长度为n的字符串p,使得字符串 s 是字符串 p 的一个子序列,只考虑英文小写字母.

进一步解释:

  • 子序列:假如有一个字符串a,我们去掉其中的一些字母(只能“去掉”,而不能交换字母的位置),得到另外一个串b,我们把b称为a的子序列。
  • 举个例子: "hhhl"可以是"hahaschool"的子序列,"sik"可以是"suika"的子序列。

思路

首先,你需要注意到其实字符串s的内容并不重要,影响答案的是字符串s的长度。

我们来考虑这样的一种思路:

假设我们构造的串是psp的子序列,我们设定:sp中的出现位置必须是字典序最小的。直白一点的说法:sp删除一些字母得到的,我们强制删除字母的时候,在连续相同的一段字母中,必须从右往左删。

举两个例子方便理解这种想法:

s = "hahl" p = "hahaschool""hahl""hahaschool"中的对应位置必须是1、2、3、10(下标从1开始)。

s = "abad" p = "aaabbbaaaddd""abad""aaabbbaaaddd"中的对应位置必须是1、4、7、10(下标从1开始)。

有了这种想法我们就可以把s在固定的p中的对应位置关系唯一地确定下来。同时我们得到了这样的结论:

假设s的每一位在p中对应的位置为p_i,字符串s的内容是s_i,那么s_{k+1}一定不会出现在p的第p_k位到p_{k+1}-1位,因为如果不这样的话,sp中的出现位置就不是“字典序最小”的了。

有了这个结论,我们就有了初步的想法,我们首先选择sp中的出现位置,这个很简单,就是\binom{n}{|s|}(其中n是要构造的p的长度,|s|是s的长度),接下来,对于每种s在p中出现位置的分布,在第p_{|s|}位之前的未填充空位,都可以填入25种字母(参见我们刚才得到的结论),在之后的空位,都可以任意填入26种字母。

这样,如果我们枚举s在p中出现的最后位置p_{|s|}(下面用k表示),我们就可以算出答案,使用下面这个式子:

ans=\sum_{k=|s|}^{n}\binom{k-1}{|s|-1}25^{k-|s|}26^{n-k}

很显然如果直接拿这个式子出答案是O(n^2)的,不满足时间限制,我们要想些办法。

观察一下上面的式子我们可以发现,可以提出26^n这一项,这样对于相同的|s|,不同的n的询问,我们只需要做一次O(n)的计算就可以全数回答。这提醒我们离线处理询问:把所有询问按照|s|为第一基准,n 为第二基准进行排序,依序处理,再按出现顺序排序,依序输出。

这样做是可行的,因为|s|最多有\sqrt{n}种(考虑极端情况:{|s|}_1 = 1,{|s|}_2 = 2,{|s|}_3 = 3,…,根据等差数列求和公式,项数最多只能到\sqrt{100000}),对于每种不同的|s|都要做一个O(n)的处理,所以总复杂度为O(n\sqrt{n}),符合题目限制。

至此本题圆满解决。

实现

 

Leave a Reply

Scroll to top