NOIP2015子串[序列DP]

题目背景

题目描述

有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重

叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。

输入输出格式

输入格式:

输入文件名为 substring.in。

第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问

题描述中所提到的 k,每两个整数之间用一个空格隔开。 第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。

输出格式:

输出文件名为 substring.out。 输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求[b]输出答案对 1,000,000,007 取模的结果。[/b]

输入输出样例

输入样例#1:

6 3 1
aabaab
aab

输出样例#1:

2

输入样例#2:

6 3 2
aabaab
aab

输出样例#2:

7

输入样例#3:

6 3 3
aabaab
aab

输出样例#3:

7

说明

对于第 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。

-----------------------------------------------------

两种思路

1.f[i][j][k][0/1] a的前i,b的前j,用了k个串,0代表所有方案,1代表必须用第i个的方案

数组开不下,考虑把i滚掉,倒序枚举j和k或者用now和pre交替

WARN:煞笔的把swap(i,j)写到了最内层,因为它查了半个多小时的错

2.不用0/1,match[i][j]表示ij最多往前匹配几个,对f前缀和优化(我还是有点玄乎)

//
//  main.cpp
//  noip2015子串
//
//  Created by abc on 16/8/28.
//  Copyright © 2016年 abc. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1005,M=205,K=205,MOD=1000000007;
int n,m,p;
char a[N],b[M];
int f[2][M][K][2],pre=1,now=0,ans=0;
void dp(){
    f[pre][0][0][0]=f[now][0][0][0]=1;
    for(int i=1;i<=n;i++,swap(now,pre))
        for(int j=1;j<=m;j++)
            for(int k=1;k<=p;k++){
                if(a[i]==b[j]) f[now][j][k][1]=(f[pre][j-1][k-1][0]+f[pre][j-1][k][1])%MOD;
                else f[now][j][k][1]=0;
                f[now][j][k][0]=(f[pre][j][k][0]+f[now][j][k][1])%MOD;
                //printf("%d %d %d  %d %d\n",i,j,k,f[now][j][k][1],f[now][j][k][0]);
            }

}
int main(int argc, const char * argv[]) {
    scanf("%d%d%d%s%s",&n,&m,&p,a+1,b+1);
    dp();
    cout<<f[pre][m][p][0];

    return 0;
}
时间: 2024-08-11 01:35:43

NOIP2015子串[序列DP]的相关文章

【学习】序列DP

做了也有一段时间的序列DP了,发现了一些规律 如果有两个字符串,一般来说,f[i][j]表示S串到第i位,T串到第j位. 如果lenS==lenT,可能可以优化到1维. 如果只有1个序列的话,一般来说f[i]表示到第i位的状态. 有一些特殊的东西:最长回文子序列是把原串倒过来然后做一遍最长公共子序列,检查一下奇偶性×2即可. 然后呢还有最长回文子串有个manacher算法来着改天要去看看. BZOJ上的题好像只做了一道呀= =好像是带计数的数列DP呀,用容斥原理搞一下就好咯. 感觉自己还是很弱还

编程之美资格赛 第二题 回文字符序列 dp

这是一道dp题,设置dp[i][j]代表的是从i到j之间的有多少个回文子串,dp[i][j] = dp[i][num[1]] +1+ dp[num[1]+1][j - 1]+1......+dp[num[j]][j-1] + 1 ,num[i] 代表的是与i字符相同的上一个字符的位置! 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串aba中,回文子序列为"a", &quo

序列DP(输出有要求)

DP Time Limit:10000MS     Memory Limit:165888KB     64bit IO Format:%lld & %llu Submit Status Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax2 < … < axm).那么就称P为S的一个上升序列.如果有多个P满足条件,那么我们想求字典

2014 Super Training #10 D 花生的序列 --DP

原题: FZU 2170 http://acm.fzu.edu.cn/problem.php?pid=2170 这题确实是当时没读懂题目,连样例都没想通,所以没做了,所以还是感觉这样散漫的做不好,有些题目明明很简单,却因为没看懂而放弃了,甚至去玩了,这样达不到太大的效果. 解法: 定义: dp[i][j]:前i个字母中有j个是属于第一个序列的标号方案种数. 则当遇到'B'时,因为要满足WB依次间歇出现,所以前面属于第一个序列的个数应该为奇数,即j&1时转移.当属于第二个序列的个数为奇数时((i-

FOJ 2170 花生的序列 dp

marketplace是Eclipse发布的一个类似AppStore一样的插件和应用平台,可以从中安装Eclipse插件等.有些旧版本的Eclipse没有安装marketpalace. 一.   marketplace的安装 打开 Eclipse,菜单栏 Help -- Install New Software,弹出 install 窗口,在 Work with 中输入 http://download.eclipse.org/releases/indigo,等待获取插件内容.然后找到 然后 Ne

2017级算法模拟上机准备篇(序列DP 进阶_1)

进阶版的序列DP 从一道题的优化开始 ModricWang的序列问题 题目描述:给定一个序列,求出这个序列中的最长上升子序列的长度. 这道题的本质还是求解一个最长上升子序列的问题 相对与之前提到过的O(n^2)的算法 我们可以重新整理思路 用O(nlogn)的思路来写,用贪心和二分优化之前的算法 我们设置新的DP数组//dp[i]代表的是当前长度为i的上升子序列的末尾元素的大小 状态转移方程为如果dp[len] < ar[i] 那么就将数ar[i]加到dp数组尾部. 反之,说明可以继续优化,显然

Neko and Aki&#39;s Prank CodeForces - 1152D (括号序列,dp)

大意: 将所有长度为2*n的合法括号序列建成一颗trie树, 求trie树上选出一个最大不相交的边集, 输出边集大小. 最大边集数一定不超过奇数层结点数. 这个上界可以通过从底层贪心达到, 所以就转化为求奇数层结点数. 然后就dp求出前$i$为'('比')'多j个的方案数, 奇数层且合法的时候统计一下贡献即可. #include <iostream> #include <iostream> #include <algorithm> #include <cstdio

[DP][NOIP2015]子串

子串 题目描述 有两个仅包含小写英文字母的字符串 A 和 B. 现在要从字符串 A 中取出 k 个 互不重叠 的非空子串, 然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案 . 输入 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开. 第二

最长无重复子串的DP实现

这道题能算DP吗?那要看是否具备最优子结构.我的分析是没有明显的子结构性质. 例如当求下表为 i 的最长无重复子串时,要考虑两类情况. (1) s[ i ] 是否在字符串s之前的位置出现过,如果没有则长度 len++ : (2) 如果出现过,分两种情况讨论(是否出出现在当前处理的子串中)(len表示当前处理的子串的长度) a> 在.那好办,直接更新len = i -  (出现位置下标) : b>不在.更好办,直接更新 len++. 分析可见,并没有什么最优子结构,DP也谈不上吧. 数据结构: