Loading

【笔记】子序列问题

对于序列 \(a(n)\),我们称 \(b(m)\)\(a\) 的子序列,当且仅当存在 \(c(m)\) 使得 \(\forall 1\le i<m,c_i< c_{i + 1}\) 并且 \(\forall 1\le i \le m, a_{c_i} = b_i\)

一个序列的子序列有 \(2^n\) 种,非空子序列有 \(2^n - 1\) 种。

子序列的子序列有 \(3^n\)​ 种,子序列的子序列的子序列有 \(4^n\) 种,依次类推。

[Ynoi2015] 盼君勿忘

每次询问一个序列所有子序列去重后的权值和之和。

考虑对每个权值算贡献,即有多少个子序列包含这个权值,简单容斥下就是 \(2^n-2^{cnt}\) 个,所以贡献就是 \((2^n-2^{cnt})x\)

例题

给定一个子序列,求有多少个本质不同子序列。

定义 \(f_i\)​ 表示以 \(i\)​ 结尾的本质不同子序列数,显然有 \(f_i = \sum f_j\)​,其中 \(s_j\)​ 是在 \(i\)​ 前面第一次出现。直接转移可以做到 \(\mathcal{O}(|S|\sum)\)​。

事实上我们有更优的容斥方法,定义状态 \(f_i\) 表示前 \(i\) 个位置有多少个本质不同的子序列数。

考虑从 \(f_i \to f_{i + 1}\),显然第 \(i + 1\) 位可选可不选,所以 \(f_{i + 1} = 2\times f_i - f_{pre_{i+ 1} - 1}\),其中 \(pre_i\) 表示 \(i\) 前面第一个和 \(S_i\) 相同的位置。时间复杂度为 \(\mathcal{O}(|S|)\)

【模板】子序列自动机

子序列自动机相对于子序列,好比后缀自动机相对与字符串,回文自动机相对与回文串。

我们观察例题的两种方法,找到二者的本质相同之处。

不难发现如果我们对于所有 \(i<j\) 使得 \(s_j\) 是在 \(i\) 之后第一次出现,连一条 \(i\to j\) 的边,那么我们就会得到一个有向无环图,即子序列自动机。

所以自动机中的一条路径与一个子序列一一对应,本质不同的子序列数就是路径数。

对于例题的第一种方法,\(f_i\)​​ 表示以 \(i\) 为终点了路径数,对于第二种方法表示前 \(i\) 个点的路径数,这样就很清晰是正确的。

例2 Distinct Subsequences

求所有子序列的本质不同子序列个数之和。

显然就是求所有子序列的子序列自动机中路径条数。

所以我们可以定义状态 \(f_i\) 表示以 \(i\) 结尾的所有子序列中,所有以 \(i\) 结尾的路径之和,那么 \(i\) 之后任意选,答案为 \(\sum 2^{n - i}f_i\)

我们枚举 \(j\)​ 进行转移,其中区间 \([j + 1,i - 1]\)​ 中等于 \(s_i\)​ 的位置不能选,其余位置任选,所以 \(f_i = \sum f_j2^{cnt_j}\)\(cnt_j\) 表示区间 \([j + 1, i - 1]\) 中不等于 \(s_i\) 的位置。

直接转移可以做到 \(\mathcal{O}(n^2)\),事实上我们发现在从小到大枚举 \(i\) 的过程中,对于 \(i\) 后面的 \(=s_i\)​ 的位置,相当于统一 \(/2\),打个标记即可。这样就可以做到线性。

posted @ 2021-10-01 20:05  7KByte  阅读(248)  评论(0编辑  收藏  举报