#lydlx05x0E26. 折叠序列 Folding
折叠序列 Folding
题目描述
比尔正在试图用折叠重复子序列的方式紧凑的表示由大写字母 A 到 Z 组成的字符序列。
例如,表示序列 AAAAAAAAAABABABCCD 的一种方式是 10(A)2(BA)B2(C)D。
他通过以下方式定义了折叠的字符序列以及它们的展开变换:
- 包含单个字符的序列被认为是折叠序列,展开它得到的序列为它本身。
- 如果 和 是两个折叠序列,并且 可以展开得到 , 可以展开得到 ,则认为 也是一个折叠序列,并且 展开得到 。
- 如果 是折叠序列,则 也是折叠序列,其中 为大于 1 的整数。如果 展开得到 ,则 展开得到 个 。
根据定义可以展开任意给出的折叠序列,现在给出原序列,请你将它折叠,并使得折叠序列包含尽可能少的字符数。
输入格式
输入包含一行由大写字母构成的字符序列,序列长度在 到 之间。
输出格式
输出包含字符数最少的折叠序列,如果答案不唯一则任意输出一个即可。
样例
AAAAAAAAAABABABCCD
9(A)3(AB)CCD
样例解释
原序列
AAAAAAAAAABABABCCD
长度为 18。
折叠表示
一种可能的折叠表示:9(A)3(AB)CCD
展开:
9(A)→AAAAAAAAA3(AB)→ABABABCCD→CCD拼接:AAAAAAAAAABABABCCD,与原序列一致。
折叠序列的字符数为 9(注意:9(A) 是 3 个字符,3(AB) 是 5 个字符,CCD 是 3 个字符,总 3+5+3=11?不对,让我们数一下:9(A)3(AB)CCD:
91 字符(1 字符A1 字符)1 字符 →9(A)共 4 字符31 字符(1 字符A1 字符B1 字符)1 字符 →3(AB)共 5 字符C1 字符C1 字符D1 字符 →CCD3 字符 总 4+5+3=12 字符。
但题目说输出 9(A)3(AB)CCD,所以样例答案就是 12 个字符?原序列长 18,压缩到 12。
但还有更短的表示吗?例如 10(A)2(BA)B2(C)D 长度:
10(A):102 字符,(1,A1,)1 → 5 字符2(BA):21,(1,B1,A1,)1 → 5 字符B:1 字符2(C):4 字符D:1 字符 总 5+5+1+4+1=16 字符,比 12 长。
所以 9(A)3(AB)CCD 是一种较优压缩。
数据范围
- 序列长度
算法分析
这是一个区间动态规划问题,要求将给定字符串折叠成最短的表示形式。
状态定义
设 表示子串 的最短折叠表示的长度(字符数)。
转移方程
-
直接拼接:将子串分成两部分 和 ,则 $dp[i][j] = \min_{i \le k < j} \{ dp[i][k] + dp[k+1][j] \}$。
-
重复模式折叠:如果子串 可以由一个更短的子串重复多次得到,那么可以用 的形式表示。 设子串长度为 ,枚举重复单元的长度 ,满足 整除 ,并且子串 重复 次等于 。 则折叠表示形式为 + + ,其长度 = 数字 的位数 + 2(括号) + 。 即 $dp[i][j] = \min \{ \text{digits}(\frac{len}{l}) + 2 + dp[i][i+l-1] \}$。
注意:如果重复单元本身可以折叠, 已经是其最短表示长度。
初始条件
单个字符:。
记录方案
为了输出折叠序列,我们需要记录每个状态的最优表示字符串。可以用一个字符串数组 存储 的最短折叠表示。
在转移时,如果找到更优长度,则更新 。
检查重复
如何快速判断 是否由 重复构成? 可以比较字符串:对于每个 整除 ,检查 是否重复 次等于 。由于长度 ≤100,可以直接比较。
复杂度
状态数 ,每个状态转移:
- 枚举分割点 :
- 枚举重复单元长度 : 总复杂度 ,对于 ,,可以接受。
实现细节
数字位数
函数 digits(x) 返回整数 的十进制位数。
检查重复
给定子串 和长度 ,检查是否由 重复组成: 对于 到 ,检查 。
更新策略
对于每个状态 ,先初始化为直接拼接(枚举 )得到的最小值,然后尝试重复折叠,如果更优则更新。
输出
最终答案为 。
样例验证
对于样例 AAAAAAAAAABABABCCD,通过 DP 可以得到最短表示之一为 9(A)3(AB)CCD。
总结
本题是区间 DP 的经典题目,关键在于处理重复子串的折叠表示。注意数字的位数和括号计入长度,以及如何检查重复模式。