【题目描述】

有两个仅包含小写英文字母的字符串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 题解的更多相关文章

  1. NOIP2015子串[序列DP]

    题目背景 无 题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重 叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个 ...

  2. Vijos1982 NOIP2015Day2T2 子串 substring 动态规划

    子串 (substring.cpp/c/pas) 题目链接 [问题描述]有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重叠 的非空子串,然后把这 k 个子串按照 ...

  3. Vijos1425子串清除 题解

    Vijos1425子串清除 题解   描述: 我们定义字符串A是字符串B的子串当且仅当我们能在B串中找到A串.现在给你一个字符串A,和另外一个字符串B,要你每次从B串中从左至右找第一个A串,并从B串中 ...

  4. NOIP2015 子串 (DP+优化)

    子串 (substring.cpp/c/pas) [问题描述] 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重 叠 的非空子串,然后把这 k 个子串按照其在字 ...

  5. LOJ2424 NOIP2015 子串 【DP】*

    LOJ2424 NOIP2015 子串 LINK 题目大意是给你两个序列,在a序列中选出k段不重叠的子串组成b序列,问方案数 首先我们不考虑相邻的两段,把所有相邻段当成一段进行计算 然后设dpi,j, ...

  6. [NOIP2015]子串 题解

    题目描述 有两个仅包含小写英文字母的字符串A和B. 现在要从字符串A中取出k个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可 ...

  7. 题解【洛谷P2679】[NOIP2015]子串

    题面 看到求方案数,还要对 \(1000000007\ (1e9+7)\) 取模,一般这样的问题都要考虑 动态规划. 我们设 \(dp_{i,j,k,0/1}\) 表示 \(A_{1\dots i}\ ...

  8. NOIP2015 子串

    #149. [NOIP2015]子串 有两个仅包含小写英文字母的字符串 AA 和 BB. 现在要从字符串 AA 中取出 kk 个互不重叠的非空子串,然后把这 kk 个子串按照其在字符串 AA 中出现的 ...

  9. [DP][NOIP2015]子串

    子串 题目描述 有两个仅包含小写英文字母的字符串 A 和 B. 现在要从字符串 A 中取出 k 个 互不重叠 的非空子串, 然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的 ...

随机推荐

  1. sqlserver插入时发生在“xxx”处关键发生错误

    今天知道了一个小技巧,当你的数据库表名为user时会sqlserver的表发生冲突,所以因该将user这样用[user],ok 一切搞定 .

  2. VC----Class Style类风格和窗口风格

    CS_BYTEALIGNCLIENT:以字节边界来对齐窗口客户区,这个风格会影响 窗口 的宽度和水平位置.实际上没有看到效果. CS_BYTEALIGNWINDOW:以字节边界来对齐窗口,这个风格会影 ...

  3. Robot Framework--08 List Variables-List变量及其用法

    转自:http://blog.csdn.net/tulituqi/article/details/7907981 一.List变量及其用法 在我们前面几篇文章里用到了很多List变量,相信以后各位也会 ...

  4. 安装CentOS7重启后提示License information

    Initial setup of CentOS Linux (core) ) [x] Creat user ) [!] License information (no user will be cre ...

  5. [c#]获取exchange中的图片

    摘要 在exchange 2007或者2010中获取的邮件内容为html标签格式,也就是一个页面.如果里面含有img标签,你会发现img标签的src属性为cid:xxxxxxxxxxxx的一串字符串, ...

  6. [MongoDB]对数组操作

    摘要 在实际开发中遇到更新某个document中的数组的值,这里做一下记录. 这里使用的驱动为 using MongoDB.Bson;using MongoDB.Driver; 相关文章 [Mongo ...

  7. 如何在JDK1.8中愉快地处理日期和时间

    如何在JDK1.8中愉快地处理日期和时间 JDK1.8新增了LocalDate和LocalTime接口,为什么要搞一套全新的处理日期和时间的API?因为旧的java.util.Date实在是太难用了. ...

  8. shell学习之路:流程控制(if)

    1.单分支if条件语句 if [ 条件判断式 ];then 程序 fi 或者 if [ 条件判断式 ] then 程序 fi 注意事项: 1.if语句使用fi结尾,和一般语言使用大括号结尾不同 2.[ ...

  9. 关于PHP位运算的简单权限设计

    写在最前面 最近想写一个简单的关于权限处理的东西,之前我也了解过用二进制数的位运算可以出色地完成这个任务.关于二进制数 的位运算,常见的就是“或.与.非”这三种简单运算了,当然,我也查看了下PHP手册 ...

  10. AngularJS API之copy深拷贝

    angular提供了一个可以复制对象的api--copy(source,destination),它会对source对象执行深拷贝. 使用时需要注意下面几点: 如果只有一个参数(没有指定拷贝的对象), ...