[vijos1982][NOIP2015]子串

Description

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

Input

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

第二行包含一个长度为n的字符串,表示字符串A

第三行包含一个长度为m的字符串,表示字符串B

Output

输出共一行,包含一个整数,表示所求方案数。

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

Sample Input

6 3 2
aabaab
aab

Sample Output

7

HINT

1$leq$n$leq$1000,1$leq$m$leq$200,1$leq$k$leq$m.
 

Solution

f[i][j][k][0/1]表示A[1..i]中的k个子串与B[1..j]相等的方案数(0表示不取A[i],1表示取)

f[i][j][k][0]=f[i-1][j][k][0/1]

f[i][j][k][1]=f[i-1][j-1][k-1][0/1]+f[i-1][j-1][k][1](A[i]==B[j])

滚动数组优化空间复杂度.

#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define M 205
#define N 1005
#define K 1000000007
using namespace std;
int f[2][M][M][2],n,m,k;
char a[N],b[M];
inline void init(){
    scanf("%d%d%d%s%s",&n,&m,&k,a+1,b+1);
    f[0][0][0][0]=1;
    for(int i=1,p,q;i<=n;++i){
        p=i&1;q=p^1;
        f[p][0][0][0]=1;
        for(int j=1;j<=m;++j)
            for(int l=1;l<=k;++l){
                f[p][j][l][0]=(f[q][j][l][0]+f[q][j][l][1])%K;
                if(a[i]==b[j]) f[p][j][l][1]=((f[q][j-1][l][1]+f[q][j-1][l-1][0])%K+f[q][j-1][l-1][1])%K;
                else f[p][j][l][1]=0;
            }
    }
    printf("%d
",(f[n&1][m][k][0]+f[n&1][m][k][1])%K);
}
int main(){
    freopen("str.in","r",stdin);
    freopen("str.out","w",stdout);
    init();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
原文地址:https://www.cnblogs.com/AireenYe/p/6083675.html