【题目描述】

有两个仅包含小写英文字母的字符串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. 平均值mean,众数mode,中值median 和 标准差stddev

    平均值mean,众数mode,中值median 和 标准差stddev 均值,众数,中位数,标称差: 均值是就全部数据计算的,它具有优良的数学性质,是实际中应用最广泛的集中趋势测度值.其主要缺点是易受 ...

  2. HTML5基本特性和新功能

    HTML5的基本特征 1.向前兼容性 核心理念——平滑过渡! 不支持html5的浏览器可以向前兼容,并不会影响web内容的显示! 2.跨平台运行性 从pc浏览器到手机.平板电脑,甚至是智能电视. 只要 ...

  3. CentOS/RHEL安装oracle 11G

    系统:RHEL6.5 + oracle11G x86_64 (CentOS上安装与此大同小异) 使用本地yum源(提前下载pdksh包),具体过程参考(适用于RHEL/CentOS):http://w ...

  4. 7Z命令行详解

    7z.exe在CMD窗口的使用说明如下: 7-Zip (A) 4.57 Copyright (c) 1999-2007 Igor Pavlov 2007-12-06 Usage: 7za <co ...

  5. Spring之FactoryBean

    首先要分辨BeanFactory 与 FactoryBean的区别, 两个名字很像,所以容易搞混 BeanFactory: 以Factory结尾,表示它是一个工厂类,是用于管理Bean的一个工厂 Fa ...

  6. MYSql存储过程的作用及语法

    1.使用了存过程,很多相似性的删除,更新,新增等操作就变得轻松了,并且以后也便于管理! 2.存储过程因为SQL语句已经预编绎过了,因此运行的速度比较快. 3.存储过程可以接受参数.输出参数.返回单个或 ...

  7. Java-java中无符号类型的处理

    在Java中,不存在Unsigned无符号数据类型,但可以轻而易举的完成Unsigned转换. 方案一:如果在Java中进行流(Stream)数据处理,可以用DataInputStream类对Stre ...

  8. DWZ框架中ajax提交文件表单的处理(关闭当前dialog + 刷新父级navTab)

    先重点关注两个js文件:dwz.ajax.js和dwz.core.js 流程: 1.回调iframeCallback <form xx enctype="multipart/form- ...

  9. Java实验2-数据库编程

    目标:掌握Java数据库编程 内容: 学生选课系统包括如下数据库表 学生表:Student(Sno,Sname,Ssex,Sage,Sdept) 课程表:Course(Cno,Cname,Ccredi ...

  10. [译]git rebase

    rebase就是重新定义你分支的起点, 分支上的commit将生成对应的新的commit并放在你指定的新的起点commit后, 分支上的老commit将被删除. rebase就是将你的分支从一个com ...