0%

2026 杭电春季联赛 3——1008-白茄子(一个比较 trick,但又没有那么 trick 的子序列 dp)

题目大意

题目大意

给定一个只包含字符 01 的字符串 SS

我们称一个序列为“茄子序列”,当且仅当该序列中逆序对的数量为奇数(在 01 序列中,逆序对数量即为子序列 10 的数量,例如 10100 有 5 个逆序对)。

对于一个序列 SS',定义 f(S)f(S') 为:将 SS' 连续划分成 kk 个子段,使得每个子段都是“茄子序列”的最小划分段数 kk。如果无论怎么划分都无法满足要求,则 f(S)=0f(S') = 0

求原字符串 SS 的所有非空子序列(共 2S12^{|S|}-1 个)的 ff 值之和。答案对 998244353998244353 取模。

数据范围

  • 测试数据组数 T5T \le 5

  • 所有给定的字符串 SS 的总长度 S107\sum |S| \le 10^7

样例数据

1
2
3
4
5
6
7
8
9
10
输入:
3
1100
10110010
01101001100101101001011001101001

输出:
4
160
981596155

样例解释

以第一组样例 1100 为例:
该字符串共有 241=152^4 - 1 = 15 个非空子序列。

  • 长度为 1 的子序列(两个 1,两个 0):逆序对均为 0(偶数),无法合法划分,ff 值为 0。

  • 长度为 2 的子序列:

    • 1100:逆序对为 0,无法合法划分,ff 值为 0。
    • 10(共有 4 个,分别由原串位置(1,3), (1,4), (2,3), (2,4)组成):逆序对数为 1(奇数),整个序列本身就是一个“茄子序列”,最少可划分为 1 段,因此 f(10)=1f(10) = 1。这部分 ff 值之和为 4×1=44 \times 1 = 4
  • 长度为 3 的子序列(两个 110,两个 100):逆序对数均为 2(偶数),且无论如何划分,都无法切分成若干个逆序对均为奇数的子段,因此 ff 值为 0。

  • 长度为 4 的子序列(1100):逆序对数为 4(偶数),同样无法合法划分,ff 值为 0。

综上所述,所有非空子序列的 ff 值之和为 4。

思路讲解

PDF

我们先看段,再看串,最后看如何前缀 dp。(注意,所谓的串,是假设我们已经从原字符串取出来了一个子序列,我们称其为,而是对这个串进行分段以后的这个段。)

image

上面其实讲的事情很简单,就是说一个段,可以用 1 的数量和逆序对数量来表征。

image

那么,怎么样求一个串的最优分段数量呢?

image

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct State {
// d[num1][rev] 表示当前已经读完某个前缀后,
// num1 就是1的个数的奇偶性,rev 就是 逆序对 数量
// 在所有“最后一个未结束子段的内部状态为 $(x,y)$”的切分方案中,前面已经结束的合法子段数的最小值。
// num1,rev 代表未结束子串状态,未结束子串允许是空串
array<array<ll, 2>, 2> d;

auto operator<=>(const State &) const = default;

[[nodiscard]] State next_state(ll op) const {
array<array<ll, 2>, 2> nd{INF, INF, INF, INF};
for (int num1 = 0; num1 < 2; ++num1) {
for (int rev = 0; rev < 2; ++rev) {
ll to_num1 = num1 ^ op, to_rev = rev ^ (op == 0 ? num1 : 0);
nd[to_num1][to_rev] = min(nd[to_num1][to_rev], d[num1][rev]);
if (rev == 1) {
nd[op][0] = min(nd[op][0], d[num1][rev] == INF ? INF : d[num1][rev] + 1);
}
}
}
return State{nd};
}
};

AC代码

AC
https://acm.hdu.edu.cn/contest/view-code?cid=1199&rid=18676

心路历程(WA,TLE,MLE……)

注意,不要在循环内新建这个变量,可以把这个变量放在外面(说白了就是建内存块,delete 析构内存慢)

注意在构造 nxt 数组的时候,一定不要忘记给已经到过的点也要建边

注意,防止哨兵值参与计算,如果是 INF 哨兵值,就直接 continue

PDF