本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

【问题描述】
有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个 互不重叠 的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案 。
【输入格式】
输入文件名为 substring.in。
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。
第二行包含一个长度为 n 的字符串,表示字符串 A。
第三行包含一个长度为 m 的字符串,表示字符串 B。
【输出格式】
输出文件名为 substring.out。
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 1,000,000,007 取模的结果。
【输入输出样例 1】
substring.in
6 3 1
aabaab
aab
substring.out
2
见选手目录下 substring/substring1.in 与 substring/substring1.ans。
【输入输出样例 2】
substring.in
6 3 2
aabaab
aab
substring.out
7
见选手目录下 substring/substring2.in 与 substring/substring2.ans。
【输入输出样例 3】
substring.in
6 3 3
aabaab
aab
substring.out
7
见选手目录下 substring/substring3.in 与 substring/substring3.ans。
【输入输出样例说明】
所有合法方案如下:
(加下划线的部分表示取出的子串)
样例 1:aab aab / aab aab
样例 2:a ab aab / a aba ab / a a ba ab / aab a ab
aa b aab / aa baa b / aab aa b
样例 3:a a b aab / a a baa b / a ab a a b / a aba a b
a a b a a b / a a ba a b / aab a a b
【输入输出样例 4】
见选手目录下 substring/substring4.in 与 substring/substring4.ans。
【数据规模与约定】
对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;
对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2;
对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m;
对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m;
对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m;
对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。

解题报告:DP

正解:

     这道题就是NOIP2015的day2T2,个人认为是一道非常有水平的DP好题,考察了对DP的综合运用,状态的设计、转移都是DP中的经典,同时前缀和优化和滚动数组的使用也很重要。

前几天我还把整个NOIP出现过的DP题给麓山信息组和我们信息组一批人讲解过一遍,这道题自然是最难的。正好自己也总结一下。

很容易想到这道题中A串每个字母只有三种可能:未被选入与B串匹配、是某一个选出来的子串的开头、是某一个选出来的子串的中间。那么我设计的状态肯定要考虑第几个串、A匹配到谁、B匹配到谁。所以我选择设计的状态为:f[kk][i][j],表示当前A选取到第kk个串,而且A串当前是i与B串的j匹配的方案数。显然A串的i若和B串的j不相等这个方案数就为0。下面考虑转移方程和转移对象。因为当前有三种可能,那么不选的情况可以不管,我们只需要管有多少种选的方案。那么就只剩两种可能了:当前这一位新开始了一个子串,或者紧接着上一个字母仍是上一个子串。

  也就是说假如新开启了一个子串,我们需要枚举上一个子串的末尾;如果紧接着那只能从上一个转过来。

  根据上面提到的,列出转移式:

  $${f[kk][i][j]=\sum_{0<=l<i}^{s[i]==ch[j]}f[kk-1][l][j]}$$

         $${=\sum_{0<=l<i}^{s[i-1]==ch[j-1]}f[kk-1][l][j] +f[kk][i-1][j-1]}$$

  可以看出如果枚举l然后转移的话,复杂度是O(n^2 m k),并不能通过所有数据点。那怎么办呢,我们考虑这个前缀和我们没有必要每次都从头for到尾,加之我们之前已经做过了,我们不妨把这个前缀和记录下来,这样可以做到O(1)转移。

  现在时间上是没问题了,但是空间却开不下,注意到转移式子中对于第k个子串,我们只需要调用第k-1个子串的信息,这也就意味着我们只需保留上一次的方案即可,再久一点可以不管了,容易想到滚动数组,可以把空间上降一个维度,具体见代码实现。

 //It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
#define RG register
const int inf = (<<);
const int MOD = ;
const int MAXN = ;
const int MAXM = ;
const int MAXK = ;
LL f[][MAXN][MAXM],S[][MAXN][MAXM],ans;//f[k][i][j]表示取到第k个串,A串匹配到i,B串匹配到j的方案数
int n,m,k;
char s[MAXN],ch[MAXM]; inline int getint()
{
RG int w=,q=; RG char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
} inline void work(){
n=getint(); m=getint(); k=getint();
scanf("%s",s+); scanf("%s",ch+);
S[][][]=; for(RG int i=;i<=n;i++) S[][i][]=;//记录前缀和
f[][][]=;//只能从0开始转过来
RG int tag=;
for(RG int kk=;kk<=k;kk++) {
tag^=; memset(S[tag],,sizeof(S[tag])); memset(f[tag],,sizeof(f[tag]));
for(RG int l1=;l1<=n;l1++) {
for(RG int l2=;l2<=min(m,l1);l2++) {
if(s[l1]!=ch[l2]) { S[tag][l1][l2]=S[tag][l1-][l2]; if(S[tag][l1][l2]>=MOD) S[tag][l1][l2]%=MOD; continue; }
f[tag][l1][l2]=S[tag^][l1-][l2-];
if(s[l1-]==ch[l2-] && l1!= && l2!=) f[tag][l1][l2]+=f[tag][l1-][l2-];
S[tag][l1][l2]=S[tag][l1-][l2]+f[tag][l1][l2];
if(f[tag][l1][l2]>=MOD) f[tag][l1][l2]%=MOD;
if(S[tag][l1][l2]>=MOD) S[tag][l1][l2]%=MOD;
}
}
}
for(RG int i=;i<=n;i++) ans+=f[tag][i][m],ans%=MOD;
printf("%lld",ans);
} int main()
{
work();
return ;
}

UOJ149 【NOIP2015】子串的更多相关文章

  1. NOIP2015子串[序列DP]

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

  2. LOJ2424 NOIP2015 子串 【DP】*

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

  3. 【uoj149】 NOIP2015—子串

    http://uoj.ac/problem/149 (题目链接) 题意 给出两个字符串A.B,问从A中取出k个互不重叠的子串按顺序组成B的方案数. Solution 一看这种题目就是字符串dp,字符串 ...

  4. NOIP2015 子串

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

  5. [NOIP2015] 子串(dp)

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

  6. [vijos1982][NOIP2015]子串

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

  7. [NOIP2015] 子串substring 题解

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

  8. NOIP2015 子串 (DP+优化)

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

  9. [DP][NOIP2015]子串

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

  10. [NOIP2015]子串 题解

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

随机推荐

  1. [转]源代码的管理和发布:以SVN为例

    FROM : http://ju.outofmemory.cn/entry/47277 前几天在微博吐槽了SVN的几个不爽的地方:.svn文件满天飞.分支管理的麻烦.不爽一般来说都是有过对比后才有如此 ...

  2. [转]java去除List中重复的元素

    java去除List中重复的元素 如果用Set ,倘若list里边的元素不是基本数据类型而是对象, 那么请覆写Object的boolean   equals(Object   obj)   和int  ...

  3. codevs2010 求后序遍历

    难度等级:白银 2010 求后序遍历 题目描述 Description 输入一棵二叉树的先序和中序遍历序列,输出其后序遍历序列. 输入描述 Input Description 共两行,第一行一个字符串 ...

  4. lecture2-NN结构的主要类型的概述和感知机

    Hinton课程第二课 一.NN结构的主要类型的概述 这里的结构就是连接在一起的神经元.目前来说,在实际应用中最常见的NN就是前向NN,他是将数据传递给输入单元,通过隐藏层最后到输出层的单元:一个更有 ...

  5. HoloLens开发手记 - 应用程序模型 App model

    HoloLens使用Universal Windows Platform (UWP)提供的应用模型.UWP应用模型定义了应用如何被安全和完全地安装.更新.版本控制和移除.它管理了应用生命周期 - 应用 ...

  6. WPF下制作的简单瀑布流效果

    最近又在搞点小东西,美化界面的时候发现瀑布流效果比较不错.顺便就搬到了WPF,下面是界面 我对WEB前端不熟,JS和CSS怎么实现的,我没去研究过,这里就说下WPF的实现思路,相当简单. 1.最重要的 ...

  7. 转载:ZooKeeper Programmer's Guide(中文翻译)

    本文是为想要创建使用ZooKeeper协调服务优势的分布式应用的开发者准备的.本文包含理论信息和实践信息. 本指南的前四节对各种ZooKeeper概念进行较高层次的讨论.这些概念对于理解ZooKeep ...

  8. js的原型链和constructor

    转载:http://www.108js.com/article/article1/10201.html?id=1092 请先瞻仰上边的这篇文章. 对象的原型链: box.__proto__.__pro ...

  9. java的HashCode方法

    总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重复: 后者元素无序,但元素不可重复. 要想保证元素不重复,可两个元素是 ...

  10. js表单提交,面向对象

    一.js表单验证之后再提交 1.普通按钮onclick函数调用表单的submit()函数 <input type=button name="submit1" value=&q ...