子串

传送门

解法:

(下面运用到了这个数据 aabaab aab)

虽然是字符串

但是发现就算是数字也是一样的

看上去像是字符串匹配 但是只是看上去

这题做法考虑dp

设dp[i][j][k]表示到A中i位置时匹配到B中j位置分成k段得到的方案数

(此时A[i]不要求等于B[j])

我们发现第一种转移不需要考虑可否连起来算一段

即可以把aab分为a a b三段

直接在dp中操作即可

但是第二种转移要考虑与前面相连共算一段

即要把aab看成一段

于是我们要多设一个数组

f[i][j][k]表示 取到A中i位置 B中j位置时 与前面相连的分成k段得到的方案数

(此时要求A[i]=B[j] 否则此时f[i][j][k]=0)

那么转移方程就出来了

若A[i]==B[j]
则f[i][j][k]=f[i-1][j-1][k]+dp[i-1][j-1][k-1]
相当于前一个位置相连的方案数累加进来
加上把之前分为多段并把当前作为新的一段的值

若A[i]≠B[j]
则f[i][j][k]=0

最后累加进答案dp[i][j][k]

最后答案就是dp[n][m][k]

还要优化空间 把i用滚动数组方式滚掉就好

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 2000000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
const int mod=1000000007;
int n,m,tk;
int a[1010],b[210],dp[210][210],f[210][210];
int main()
{
    scanf("%d%d%d",&n,&m,&tk);
    string s;
    cin>>s;
    rep(i,1,n) a[i]=s[i-1]-'a';
    cin>>s;
    rep(i,1,m) b[i]=s[i-1]-'a';
    dp[0][0]=1;
    rep(i,1,n)
    {
        dwn(j,min(m,i),1)
        {
            dwn(k,min(tk,j),1)
            {
                if(a[i]==b[j]) f[j][k]=(f[j-1][k]+dp[j-1][k-1])%mod;
                else f[j][k]=0;
                dp[j][k]=(f[j][k]+dp[j][k])%mod;
            }
        }
    }
    printf("%d\n",dp[m][tk]);
    return 0;
}

posted @ 2019-06-30 19:56  zmy蒟蒻  阅读(210)  评论(0编辑  收藏  举报