2015提高组 子串

题目描述

有两个仅包含小写英文字母的字符串 AA 和 BB。

现在要从字符串 AA 中取出 kk 个互不重叠的非空子串,然后把这 kk 个子串按照其在字符串 AA 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 BB 相等?

注意:子串取出的位置不同也认为是不同的方案。

输入输出格式

输入格式:

 

第一行是三个正整数 n,m,kn,m,k,分别表示字符串 AA 的长度,字符串 BB 的长度,以及问题描述中所提到的 kk,每两个整数之间用一个空格隔开。

第二行包含一个长度为 nn 的字符串,表示字符串 AA。

第三行包含一个长度为 mm 的字符串,表示字符串 BB。

 

输出格式:

 

一个整数,表示所求方案数。

由于答案可能很大,所以这里要求输出答案对 10000000071000000007 取模的结果。


lv神Day6T2,一个爆水的dp,呃,然而净顾着写T1,还忘了删注释

首先dp方程是好推的,dp[i][j][l][0]代表主串到i,模式串到j,分了l段,当前位可取也可不取

dp[i][j][l][1]代表主串到i,模式串到j,分了l段,当前位必须取

dp[i][j][l][1]=dp[i-1][j-1][l][1]+dp[i-1][j-1][l-1][0]

dp[i][j][l][0]=dp[i][j][l][1]+dp[i-1][j][l][0]

然后就发现MLE了,怎么解决呢?

我们将这个dp数组看做一个网格图

每一个dp[i][j][l][0],都是从他的左上角和他的上方的两个方格处转移过来的

所以我们将循环倒过来,这样就可以压缩我们的状态,提前计算出要处理的方格的上面的方格,再从前面的方格转移

如下:
dp[j][l][1]=dp[j-1][l][1]+dp[j-1][l-1][0]

dp[j][l][0]=dp[j][l][1]+dp[j][l][0]

然后就是基础操作

下面给出代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int dp[1006][206][2];
char a[100006];
char b[100006];
int n,m,k;
int mod=1000000007;
int main(){
    n=rd();
    m=rd();
    k=rd();
    scanf("%s%s",a+1,b+1);
    dp[0][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=m;j>=1;j--){
            if(a[i]==b[j]){
                for(int v=k;v>=1;v--){
                    dp[j][v][1]=(dp[j-1][v-1][0]+dp[j-1][v][1])%mod;
                    dp[j][v][0]=(dp[j][v][1]+dp[j][v][0])%mod;
                }
            }
            else for(int v=1;v<=k;v++) dp[j][v][1]=0;
        }
    }
    printf("%d",dp[m][k][0]);
    return 0;
}

 

posted @ 2018-09-27 20:11  Bruce--Wang  阅读(125)  评论(0编辑  收藏  举报