[DP]【NOIP2015D2T2】子串 题解

传送门
洛谷:https://daniu.luogu.org/problem/show?pid=2679
UOJ:http://uoj.ac/problem/149

解题分析

一开始感觉像01背包,不过推了好久模型都建不起来,然后看了题解,三维的

f[i][j][k][0/1] 表示A串匹配到第i位,B串匹配到第j位,用了k个子串的方案数,其中第i位不要/要加入

那么如果不要i,就直接前一状态 f[i1][j][k] 推过来
如果要i,那就分是否跟前面一个子串连起来,如果连,说明i-1位也要选,推 f[i1][j1][k][1] ,否则i作为一个独立子串,前面就是A前i-1位,B前j-1位,有k-1个子串的情况推过来,推 f[i1][j1][k1]

注意到都是i-1,可以滚动数组优化空间。

复杂度:
时间: O(nmk)
空间: O(4mk)

#include<cstdio>
#include<cstring>
using namespace std;
const int tt=1e9+7;
int n,m,p,f[2][205][205][2];
char a[1005],b[205];
int main()
{
    freopen("substring.in","r",stdin);
    freopen("substring.out","w",stdout);
    scanf("%d%d%d",&n,&m,&p); scanf("%s%s",a+1,b+1);
    memset(f,0,sizeof(f)); f[0][0][0][0]=1;
    for (int i=1,c=1;i<=n;i++,c^=1){
        memset(f[c],0,sizeof(f[c]));
        f[c][0][0][0]=1;
        for (int j=1;j<=m;j++)
            for (int k=1;k<=p;k++){
                f[c][j][k][0]=(f[c^1][j][k][0]+f[c^1][j][k][1])%tt;
                if (a[i]==b[j]) f[c][j][k][1]=((long long)f[c^1][j-1][k-1][1]+f[c^1][j-1][k][1]+f[c^1][j-1][k-1][0])%tt;
            }
    }
    printf("%d\n",(f[n&1][m][p][0]+f[n&1][m][p][1])%tt);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/try__jhf/article/details/78330757
今日推荐