【DP总结】【字符串】【子串】
来源:互联网 发布:清除注册表的软件 编辑:程序博客网 时间:2024/05/29 13:14
题目描述】
有两个仅包含小写英文字母的字符串A和B。现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串B相等?注意:子串取出的位置不同也认为是不同的方案。
由于答案可能很大,所以这里要求输出答案对1,000,000,007取模的结果。
【样例输入1】
6 3 1
aabaab
aab
【样例输出1】
2
【样例输入2】
6 3 2
aabaab
aab
【样例输出2】
7
【样例输入3】
6 3 3
aabaab
aab
【样例输出3】
7
【数据规模与约定】
对于100%的数据:1≤n≤1000,1≤m≤200,1≤k≤m。
【解法】
还好吧……一个DP……不过细节比较多,难度不小。
我们令f[i][j][k][0/1]表示A串用了前i个字符,B串已覆盖前j个字符,目前为止已经选了k个子串,最后的0/1表示A串的这个字符选了没有(0没选,1选了)。
为了得出状态转移方程,我们分情况讨论:
先看f[i][j][k][1](当前位选了),显然当且仅当a[i]=b[j]的时候它才有意义,否则f[i][j][k][1]=0。
到这个状态有三种方法:
1. 上一位没有选,新开一个子串
2. 上一位选了,延续这个子串
3. 上一位选了,但是仍然新开一个子串
因此,我们有
f[i][j][k][1]=f[i-1][j-1][k-1][0]+f[i-1][j-1][k][1]+f[i-1][j-1][k-1][1]。
状态转移方程中的三项分别对应上述三种情况。注意,因为我们规定了A的这一位必须选(因为状态的最后一维是1),所以所有前驱状态一定是f[i-1][j-1][…][…]。
然后讨论另一种情况:这个字符不选。
这个比较简单,到这个状态有两种方法:
1. 上一位没有选,现在仍然不选
2. 上一位选了,结束这个子串
因此,我们有
f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]。
合起来就是
f[i][j][k][1]=f[i-1][j-1][k-1][0]+f[i-1][j-1][k][1]+f[i-1][j-1][k-1][1](a[i]=b[j])
f[i][j][k][1]=0(a[i]!=b[j])
f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]
状态转移方程有了,边界也容易确定:f[0][0][0][0]=1。至于最终答案,显然是f[n][m][k][0]+f[n][m][k][1]。
这里有O(nmk)个状态,转移是O(1)的,因此总复杂度O(nmk),完全够用(毕竟常数不大)。
然后,注意一些可能越界的问题(j/k=0的时候不要j/k-1),再用滚动数组压掉第一维,就可以AC了。
总结
最长公共字串问题一般需要考虑的点其实都包含在这道题里面了。
就是 第 i 位 选还是不选。
选 或者 不选 可以 由 上一个状态中哪一种状态得到。
Fighting!
- 【DP总结】【字符串】【子串】
- noip 2015 T5 子串 字符串dp
- 【DP总结】【字符串】【POJ1141】
- NOIP 2015 Day 2 substring 子串(字符串 dp)
- 回文字符串【最长公共子序列】【DP】
- dp---两个字符串最长公共子序列
- 【noip2015】【DP】子串
- NOIP2015 子串 DP
- noip2015 子串 dp
- NOIP2015 子串 dp
- [DP] NOIP2015 子串
- 九度OJ 1252:回文子串 (字符串处理、DP)
- 编程珠玑: 15章 字符串 15.2寻找字符串中的最长重复子串 -------解题总结
- PHP开发之字符串长度以及字符串子串截取相关函数总结
- 字符串最大子串
- 字符串判断子串
- java字符串子串
- 字符串子串
- 【笔记】配置Python脚本自启动服务
- MFC中Dialog中添加菜单
- 欢迎使用CSDN-markdown编辑器
- NOIP 2005 过河
- Codeforces Divisibility by Eight
- 【DP总结】【字符串】【子串】
- HTTP页面状态码
- Java中启动线程start和run方法
- 【vijos】【生成树】最小生成树的最小完全图
- 反射机制
- 使用AngularJS修改、删除表格数据
- 通用的增删改查方法(反射)附带MySQL数据库连接
- [openjudge] 数据包的调度机制(dp好题)
- NOIP 2004 虫食算