Mysterious Code (状态机 + dp + kmp)

题目链接

哈哈哈今天晚上ig VS tes, ig 居然赢了,作为極粉的我真的很开心, 写一下今天下午做的题目吧,是一个kmp + 状态机的题目, 之前做过一个这样的题目,但是奈何做题数量真的不多,一开始还是不清楚做题方向,还在向贪心的方向上想了一会(指半小时),后来知道是dp之后自己也是独立的做出来了, 想想自己还是有一点实力, 就是要自信点,大胆的去猜和做,就像小ig一样冲冲冲, 这几天没有ig的比赛了,那就潜心研究下算法!!

首先先想一下这道题目为什么可以利用dp来做呢,其实这道题目也是在进行枚举,对于将可能影响到最佳答案的状态保存下来,对于每个星号都在进行枚举其可能的值,(其实题目中也隐晦的告诉我这道题目要用dp,就是题目中提到了所有的字母都是小写字母,这样我们明确了可以枚举的种类, 但是为什么我在写题解的时候才发现这一点。。),然后剩下的就是正常的kmp 加状态机了。

这里还需要注意一下当 j == len 时,我们需要将值更新到ne[j] 上,当然其实0 - ne[j] 都应该更新上,只是不影响最优解罢了。

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1100, M = 60;

char a[N], b[N], c[N];

int ne_c[N], ne_b[N], f[N][M][M];

int main()
{
	scanf("%s%s%s", a + 1, b + 1, c + 1);
	int len_a = strlen(a + 1), len_b = strlen(b + 1), len_c = strlen(c + 1);
	for (int i = 2, j = 0; i <= len_c; i++)
	{
		while (j && c[j + 1] != c[i]) j = ne_c[j];
		if (c[j + 1] == c[i]) j++;
		ne_c[i] = j;
	}
	for (int j = 0, i = 2; i <= len_b; i++)
	{
		while (j && b[j + 1] != b[i]) j = ne_b[j];
		if (b[j + 1] == b[i]) j++;
		ne_b[i] = j;
	}
	memset(f, -0x3f, sizeof f);

	f[1][0][0] = 0;
	for (int i = 1; i <= len_a; i++)
	{
		for (char jz = 'a'; jz <= 'z'; jz++)
			for (int k = 0; k <= len_b - 1; k++)
				for (int r = 0; r <= len_c - 1; r++)
				{
					int t1 = k, t2 = r, t = 0;
					char j = a[i];
					if (a[i] == '*') j = jz;
					while (t1 && b[t1 + 1] != j) t1 = ne_b[t1];
					if (b[t1 + 1] == j) t1++;
					while (t2 && c[t2 + 1] != j) t2 = ne_c[t2];
					if (c[t2 + 1] == j) t2++;
					if (t2 == len_c) t2 = ne_c[t2], t--;
					if (t1 == len_b) t1 = ne_b[t1], t++;
					f[i + 1][t1][t2] = max(f[i + 1][t1][t2], f[i][k][r] + t);
				}
	}
	int res = -1e9;
	for (int i = 0; i <= len_b; i++)
		for (int j = 0; j <= len_c; j++) res = max(res, f[len_a + 1][i][j]);

	printf("%d", res);



	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值