题意
给你两个串s,t和一个数k,询问是否存在s的k个不重叠子串按原顺序排列后能组成 t,
数据范围
$|s|<1e5$,$|t|<1e5$,$k<100$,时间30s
题解
设状态$dp1[i][j]$代表串$s$从$s[1]$匹配到$s[i]$的时候选择了$k$个不重叠子串后,能够匹配到t串到最远位置。
设状态$dp2[i][j]$代表串s从$s[1]$匹配到$s[i]$的时候选择了$k$个不重叠子串且最后一个子串以$s[i]$结尾后,能够匹配到t串到最远位置。
根据定义$dp1[i][j]=max(dp2[t][j]), \forall t<=i$,于是简单的写出了转移式子:$dp1[i][j]=max(dp1[i-1][j],dp2[i][j])$
复杂的是$dp2[i][j]$不好得到,根据定义,$dp2[i][j]$一定会选择$s[i]$作为结尾的,现在分两类来讨论:
$s[i]$单独为一个子串,那么可以由$dp1[i-1][j-1]$转移过来,
$s[i]$可能不单独为一个子串,是跟前面的某串拼在一起的,那么可以由$dp2[i-1][j]$转移过来。
知道了转移来源,但是状态转移过来了,值要怎么更新呢?处理不好的话,更新是个麻烦事,这里我们预处理出$t$串里面从$t[1]$到$t[i]$中字符$ch$最后一次出现的位置,成为$max_index_before[i][ch]$
于是我们就有了转移式:
1 | dp2[i][j]=max( |
最后处理一下边界情况,把输入进来的s变成"@&"+s
,把t变成"@"+t
,k增大1,边界就简单了。最终答案在$dp1[n][k]$中。
时间复杂度O(nk)
做完了之后翻了下题解,没有人用我这方法做这个题目。。。。。。
正解如下:
考虑$dp[i][j]$就是我上文所谈到的$dp1[i][j]$,他没有$dp2[i][j]$,所以不能像我那样转移了。用到了“我为人人”的转移思路,$dp[i][j]$如果转移走的时候花费一次取子串,就能够转移到$dp[i+len][j+1]$,其中len代表lcp(s.suffix(i+1),t.suffix(dp[i][j]+1))
,这个地方的lcp可以用后缀数组+rmq预处理优化为O(1),如果不花费就转移到了$dp[i+1][j]$。总体上时间复杂度为O(nlogn+nk),时间复杂度较前一个做法偏高,代码也很长。
事实也是如此
1 |
|
1 |
|
- 本文作者: fightinggg
- 本文链接: http://fightinggg.github.io/yilia/yilia/POROLT.html
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!