用 leni,j 表示 a 串中以 a[i] 为结尾的后缀,和 b 串中以 b[i] 为结尾的后缀匹配的最长长度,这个可以用简单的 O(nmk) 的预处理求出
设计状态: fi,j,k 表示 a 串中以 a[i] 为结尾的后缀,和 b 串中以 b[j] 为结尾的后缀匹配,a串中k个子串加起来和 b[1]...b[j] 相等,状态转移方程:
for(k=1 to K)
for(i=1 to N)
for(j=1 to M)
for(l=1 to len[i][j])
for(t=1 to l)
f[i][j][k]+=f[t][l][k-1]
上述的时间复杂度在最差情况下是 O(NM4) 约等于 1.6×1012 ,空间复杂度 O(nmk) 约等于 4×107 ,完爆
观察方程
这道题我其实只用了一小会就写出正解了,但是由于没看到“输出答案对1,000,000,007取模的结果”竟然查错查了一上午!
//NOIP2015 子串 动态规划
#include
#include
#define p 1000000007
#define ll long long
#define maxn 1010
#define maxm 210
using namespace std;
ll f[maxn][maxm][2], s[maxn][maxm][2], ss[maxn][maxm][2],
len[maxn][maxm], N, M, K;
char a[maxn]={0}, b[maxm]={1};
void init()
{
ll i, j, l;
scanf("%lld%lld%lld%s%s",&N,&M,&K,a+1,b+1);
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
for(l=1;a[i-l+1]==b[j-l+1];len[i][j]=l++);
}
void dp()
{
ll i, j, k;
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
{
f[i][j][1]=len[i][j]==j;
s[i][j][1]=s[i-1][j][1]+f[i][j][1];
ss[i][j][1]=ss[i-1][j-1][1]+s[i][j][1];
}
for(k=2;k<=K;k++)
{
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
{
f[i][j][k&1]=(ss[i-1][j-1][~k&1]-ss[max((ll)0,i-len[i][j]-1)][max((ll)0,j-len[i][j]-1)][~k&1])%p;
s[i][j][k&1]=(s[i-1][j][k&1]+f[i][j][k&1])%p;
ss[i][j][k&1]=(ss[i-1][j-1][k&1]+s[i][j][k&1])%p;
}
}
}
int main()
{
ll i, ans;
init();
dp();
for(i=M,ans=0;i<=N;ans=(ans+f[i++][M][K&1])%p);
printf("%lld\n",(ans+p)%p);
return 0;
}