传送门
解法:
(下面运用到了这个数据 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;
}