链接:https://www.luogu.org/problem/show?pid=2679
题解:
1.求方案数,结合数据范围,可以考虑用DP解
2.令f[i][j][k][0/1]表示A串用了前i个字符,B串已覆盖前j个字符,目前为止已经选了k个子串,最后的0/1表示A串的这个字符选了没有(0没选,1选了)。
3.若当前字符选了,显然当且仅当a[i]=b[j]的时候它才有意义,否则f[i][j][k][1]=0。
到这个状态有三种方法:
(1). 上一位不选,新开一个子串
(2). 上一位选了,延续这个子串
(3). 上一位选了,新开一个子串
根据dp数组的定义,可以得到
f[i][j][k][1]=f[i-1][j-1][k-1][0]+f[i-1][j-1][k][1]+f[i-1][j-1][k-1][1]。
4.若当前字符不选。
(1). 上一位不选,现在仍然不选
(2). 上一位选了,现在不选
故f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]。
总的方程式
f[i][j][k][1]=f[i-1][j-1][k-1][0]+f[i-1][j-1][k][1]+f[i-1][j-1][k-1]1
f[i][j][k][1]=0(a[i]!=b[j])
f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]
边界:f[0][0][0][0]=1。
最终答案:f[n][m][k][0]+f[n][m][k][1]。
复杂度O(nmk)
考虑到空间可能爆掉,用滚动数组压掉第一维即可
写的很心累QAQ
各种细节错QAQ
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 1000000007
#define Maxn 2020
int f[2][Maxn][Maxn][2];
int main()
{
// freopen("2015substring.in","r",stdin);
// freopen("2015substring.out","w",stdout);
int n,m,k,d=1;
char a[Maxn],b[Maxn];
scanf("%d %d %d %s %s",&n,&m,&k,a+1,b+1);
f[0][0][0][0]=1;
for(int i=1;i<=n;i++,d=!d)
for(int j=0;j<=i&&j<=m;j++)
for(int h=0;h<=k&&h<=j&&h<=i;h++)
{
f[d][j][h][0]=0;
if(i-1>=j)
{
(f[d][j][h][0]+=f[!d][j][h][0])%=MOD;
(f[d][j][h][0]+=f[!d][j][h][1])%=MOD;
}
f[d][j][h][1]=0;
if(j&&a[i]==b[j])
{
if(h)
{
(f[d][j][h][1]+=f[!d][j-1][h-1][0])%=MOD;
(f[d][j][h][1]+=f[!d][j-1][h-1][1])%=MOD;
}
(f[d][j][h][1]+=f[!d][j-1][h][1])%=MOD;
}
}
printf("%d\n",f[!d][m][k][0]+f[!d][m][k][1]);
return 0;
}