[NOIpTG2015]子串——[计数DP]

在这里插入图片描述
【题意分析】

这种dp题也就是按照套路来,先设一个四维的状态:dp[i][j][k][l]就是第一个串前i个,第二个串前j个,取了k段,第二个串当前位置取不取(0不取1取)的方案总数

计数dp嘛,分类讨论:

如果枚举的位置两个字符相同,那么就表明可以取或不取

d p i , j , k , 0 = d p i − 1 , j , k , 0 + d p i − 1 , j , k , 1 dp_{i,j,k,0}=dp_{i-1,j,k,0}+dp_{i-1,j,k,1} dpi,j,k,0=dpi1,j,k,0+dpi1,j,k,1

d p i , j , k , 1 = d p i − 1 , j − 1 , k − 1 , 1 + d p i − 1 , j − 1 , k − 1 , 0 + d p i − 1 , j − 1 , k , 1 dp_{i,j,k,1}=dp_{i-1,j-1,k-1,1}+dp_{i-1,j-1,k-1,0}+dp_{i-1,j-1,k,1} dpi,j,k,1=dpi1,j1,k1,1+dpi1,j1,k1,0+dpi1,j1,k,1

//对第二个naive方程的解释:这个字符取了,可能上个字符取了,连成一段或者另起一段,或者上个字符不取,那么必定另起一段。

如果不同,那么就只能不取

d p i , j , k , 0 = d p i − 1 , j , k , 0 + d p i − 1 , j , k , 1 dp_{i,j,k,0}=dp_{i-1,j,k,0}+dp_{i-1,j,k,1} dpi,j,k,0=dpi1,j,k,0+dpi1,j,k,1

d p i , j , k , 1 = 0 dp_{i,j,k,1}=0 dpi,j,k,1=0

就好了,然后很明显第一维可以滚动掉(大部分计数dp都可以滚动掉一维),就可以过了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 1010
#define MAXM 205
#define qy 1000000007
using namespace std;

char s1[MAXN], s2[MAXN];
int dp[2][MAXM][MAXM][2], n, m, K, now, pre;

int main () {
	scanf ("%d%d%d", &n, &m, &K), scanf ("%s", s1 + 1), scanf ("%s", s2 + 1);
	dp[0][0][0][0] = dp[1][0][0][0] = 1, now = 0, pre = 1;
	for (register int i = 1; i <= n; i++) {
		now ^= 1, pre ^= 1;
		for (register int j = 1; j <= m; j++)
			for (register int k = 1; k <= K; k++) {
				if (s1[i] == s2[j]) {
					dp[now][j][k][0] = (dp[pre][j][k][0] + dp[pre][j][k][1]) % qy;
					dp[now][j][k][1] = ((dp[pre][j - 1][k - 1][0] + dp[pre][j - 1][k - 1][1]) % qy + dp[pre][j - 1][k][1]) % qy;
				}
				else {
					dp[now][j][k][0] = (dp[pre][j][k][0] + dp[pre][j][k][1]) % qy;
					dp[now][j][k][1] = 0;
				}
			}
	}
	return printf ("%d\n", (dp[n & 1][m][K][0] + dp[n & 1][m][K][1]) % qy), 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值