本文作者: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. vs2015企业版太大了

    安装教程 http://www.cnblogs.com/mephisto/archive/2015/07/22/4666032.html#!comments 新功能 http://news.cnblo ...

  2. wap页面笔记

    wap页面是自行应页面 必须在head中加入 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1 ...

  3. 前后端分离工具之ftl-server

    文章来源:https://www.npmjs.com/package/ftl-server 源代码可参考:https://github.com/szmtcjm/ftl-server/blob/mast ...

  4. Webwork 学习之路【06】Action 调用

    一路走来,终于要开始 webwork 核心业务类的总结,webwork 通过对客户端传递的 web 参数重新包装,进行执行业务 Action 类,并反馈执行结果,本篇源码分析对应下图 WebWork ...

  5. mvc5+ef6+Bootstrap 项目心得--身份验证和权限管理

    1.mvc5+ef6+Bootstrap 项目心得--创立之初 2.mvc5+ef6+Bootstrap 项目心得--身份验证和权限管理 3.mvc5+ef6+Bootstrap 项目心得--WebG ...

  6. 告别编译运行 ---- Android Studio 2.0 Preview发布Instant Run功能

    以往的Android开发有一个头疼的且拖慢速度的问题,就是你每改一行代码要想看到结果必须要编译运行到手机或者模拟器上,而且需要从头(可能是登录界面)一直点击到你修改的界面为止.开发一个完整的Andro ...

  7. .net程序员转行做手游开发经历(一)

    从辞职到自己开发游戏也有几个月的时间了,游戏也已经在AppStore上线了,我觉得我有必要写点东西,算是留下的一些记忆,也可以和广大博友分享下自己的创业经历,这可能不是一篇成功的创业经历,因为故事还在 ...

  8. .Net分布式异常报警系统-简介

    系统简介 分布式异常报警系统就是收集系统运行过程中产生的未处理异常,检查系统运行的状态,并将异常信息统一发送到服务端,由服务端将信息通知到相关的责任人.  问题 我们在项目开发中可能遇到以下几个问题: ...

  9. Windows 10 自动升级画面

  10. Sql视图创建语句

    create view [dbo].[AllUsers] as select u.UserId, u.Firstname, u.Lastname, u.ts, am.Email, au.UserNam ...