[NOIP2015] 子串substring 题解
【题目描述】
有两个仅包含小写英文字母的字符串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了。
贴个代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=,maxm=;
int n,m,c,i=,f[][maxm][maxm][];
char a[maxn],b[maxm];
int main(){
#define MINE
#ifdef MINE
freopen("2015substring.in","r",stdin);
freopen("2015substring.out","w",stdout);
#endif
scanf("%d%d%d %s %s",&n,&m,&c,a+,b+);
f[][][][]=;
for(int d=;d<=n;d++,i=!i)for(int j=;j<=d&&j<=m;j++)for(int k=;k<=j&&k<=d&k<=c;k++){
f[i][j][k][]=;
if(d->=j){
(f[i][j][k][]+=f[!i][j][k][])%=;
(f[i][j][k][]+=f[!i][j][k][])%=;
}
f[i][j][k][]=;
if(j&&a[d]==b[j]){
if(k){
(f[i][j][k][]+=f[!i][j-][k-][])%=;
(f[i][j][k][]+=f[!i][j-][k-][])%=;
}
(f[i][j][k][]+=f[!i][j-][k][])%=;
}
}
printf("%d\n",(f[!i][m][c][]+f[!i][m][c][])%);
#ifndef MINE
printf("\n--------------------DONE--------------------\n");
for(;;);
#endif
return ;
}
【后记】
去年联赛的Day2 T2……难度还可以,主要是状态表示和转移方程比较麻烦,也不太好想,有些细节问题略恶心。
很久没刷过DP了……自己DP本来就弱,不过好歹自己想出来了解法,也算是个安慰吧(我才不会说其实我已经从各种渠道知道了这题的复杂度是O(nmk)的)。
为了这题废了一节课……努力吧……
[NOIP2015] 子串substring 题解的更多相关文章
- NOIP2015子串[序列DP]
题目背景 无 题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重 叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个 ...
- Vijos1982 NOIP2015Day2T2 子串 substring 动态规划
子串 (substring.cpp/c/pas) 题目链接 [问题描述]有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重叠 的非空子串,然后把这 k 个子串按照 ...
- Vijos1425子串清除 题解
Vijos1425子串清除 题解 描述: 我们定义字符串A是字符串B的子串当且仅当我们能在B串中找到A串.现在给你一个字符串A,和另外一个字符串B,要你每次从B串中从左至右找第一个A串,并从B串中 ...
- NOIP2015 子串 (DP+优化)
子串 (substring.cpp/c/pas) [问题描述] 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重 叠 的非空子串,然后把这 k 个子串按照其在字 ...
- LOJ2424 NOIP2015 子串 【DP】*
LOJ2424 NOIP2015 子串 LINK 题目大意是给你两个序列,在a序列中选出k段不重叠的子串组成b序列,问方案数 首先我们不考虑相邻的两段,把所有相邻段当成一段进行计算 然后设dpi,j, ...
- [NOIP2015]子串 题解
题目描述 有两个仅包含小写英文字母的字符串A和B. 现在要从字符串A中取出k个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可 ...
- 题解【洛谷P2679】[NOIP2015]子串
题面 看到求方案数,还要对 \(1000000007\ (1e9+7)\) 取模,一般这样的问题都要考虑 动态规划. 我们设 \(dp_{i,j,k,0/1}\) 表示 \(A_{1\dots i}\ ...
- NOIP2015 子串
#149. [NOIP2015]子串 有两个仅包含小写英文字母的字符串 AA 和 BB. 现在要从字符串 AA 中取出 kk 个互不重叠的非空子串,然后把这 kk 个子串按照其在字符串 AA 中出现的 ...
- [DP][NOIP2015]子串
子串 题目描述 有两个仅包含小写英文字母的字符串 A 和 B. 现在要从字符串 A 中取出 k 个 互不重叠 的非空子串, 然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的 ...
随机推荐
- JSP 原理
参考文献:http://www.cnblogs.com/xdp-gacl/p/3764991.html 一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都 ...
- python中的not具体使用及意思
python中的not具体使用及意思 name='' while not name: name=raw_input(u'请输入姓名:') print name python中的not具体表示是什么: ...
- php瀑布流,把一个数组分4个数组,按照时间排序
简单介绍:把一个数组分成4个数组,取其中1的倍数 <?php $arr = array( ', ', ', ', ', ', ', ', ', ', ', ', ', ); foreach($a ...
- CSS样式优先级
关于CSS样式优先级 一般情况下: [1位重要标志位] > [4位特殊性标志] > 声明先后顺序 !important > [ id > class > tag ] 使用 ...
- VS中修改站点运行方式(集成 Or 经典)
以前写过一篇博客使用HttpHander截取用户请求. 写进Web.Config时..运行会报 在集成环境下不能使用站点配置 就想改成经典..但是不会改..还修改过Framework配置什么的.. 那 ...
- Security Test Cases
https://www.owasp.org/index.php/OWASP_Testing_Guide_v4_Table_of_Contents Username Enumeration Vulner ...
- 如何在JDK1.8中愉快地处理日期和时间
如何在JDK1.8中愉快地处理日期和时间 JDK1.8新增了LocalDate和LocalTime接口,为什么要搞一套全新的处理日期和时间的API?因为旧的java.util.Date实在是太难用了. ...
- C语言内存管理(转)
伟大的Bill Gates 曾经失言: 640K ought to be enough for everybody — Bill Gates 1981 程序员们经常编写内存管理程序,往往提心吊胆.如果 ...
- 清空mysql表后,自增id复原
alter table `ajy_servercategory` AUTO_INCREMENT=1; alter table `Table_Name` AUTO_INCREMENT=n; 一.清除my ...
- JavaScript 学习笔记 -- Function
JS 中 函数.继承.闭包.作用域链... 一直都是硬伤,一碰到这样的问题头就大了.但是如果我继续着说:我不会,就真的无药可救了.要勇敢地说出:我的字典里就没有不会这个词,吼吼..正好昨天在书城里看了 ...