[noip2015]子串 题解

可以说是出得十分好的一道dp题目了,要用到滚动数组,前缀和优化。

首先,我们考虑状态,f[k][i][j]表示第一个串到i位,第二个串到j位,分了k段的方案数。
首先,如果s1[i]==s2[j]的话,f[k][i][j]=sigema(f[k-1][l][j-1])(0<=l<i)的这都可以作为一个新段。特别的,如果s1[i-1]==s2[j-1]的话,及可以归到上一段,f[k][i][j]+=f[k-1][i-1][j-1]。
注意到这样状态是nmk的,第一个求和转移是n的,显然过不了啊,但是,我们发现,求和得很有规律,我们可以保存一下sigima(f[k][l][j])(0<=l<i),要用的时候O(1)转移就好了。这样,时间复杂度就成了O(nmk),可以过了。

但是,这样空间还是会承受不了,但我们发现f[k]都只和f[k-1]有关,就可以滚动数组解决了。

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int f[2][1005][205];
int tmp[2][1005][205];
int n,m,K,ans;
char A[1005],B[205];
int main()
{
	freopen("in.txt","r",stdin);
	scanf("%d%d%d",&n,&m,&K);
	scanf("%s%s",A+1,B+1);
	f[0][0][0]=1;
	for(int i=0;i<=n;i++)tmp[0][i][0]=1;
	for(int k=1;k<=K;k++)
	{
		memset(tmp[k&1],0,sizeof(tmp[k&1]));
        memset(f[k&1],0,sizeof(f[k&1]));
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
			{
				if(A[i]==B[j])
				{
					f[k&1][i][j]=tmp[(k+1)&1][i-1][j-1];
					if(A[i-1]==B[j-1])f[k&1][i][j]=(f[k&1][i][j]+f[k&1][i-1][j-1])%mod;
				}
				tmp[k&1][i][j]=((tmp[k&1][i][j]+f[k&1][i][j])%mod+tmp[k&1][i-1][j])%mod;
			}
	}
	for(int i=1;i<=n;i++)ans=(ans+f[K&1][i][m])%mod;
	cout<<ans;
	return 0;
}

总的来说,这道题出得是特别的好。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值