2022ICPC网络赛 L LCS-like Problem(DP 子序列自动机)
L LCS-like Problem(DP 子序列自动机)
题目:
给出两个串s, t。请找出一个最长的子序列
思路:
题目名字是LCS,且题意比较符合DP的定义,优先考虑DP而非字符串来求解问题。
题目要求在s中找一个最长的满足题意的子序列。那么我们的状态表示一定是跟s有关的,又可以知道本题的转移一定是跟字符存在关系的。根据经验,可以定义出
转移的时候,对于
实现:
这里解答两个点,其一是对于f数组的定义。由于动态规划的无后效性,我们可以知道我们每次转移的时候只需要看最后一个字符就可以了。但是有一个问题,当最后一个字符
其二是关于序列自动机这个东西。其实这个知识点还挺复杂的,详情可以观看下方链接。不过本题主要只是运用其思想,本题自动机状态非常简化,只需要保存字符
https://blog.csdn.net/Berserker____/article/details/109062238
#include <bits/stdc++.h>
using namespace std;
const int N = 500005;
char s[N], t[N];
int n, m;
int vis[26]; //t中是否已经含有i
int ban[26][26]; //i的后面不能出现j 因为是子序列
int f[N][26]; //从s的前i个字符选出的子序列,且最后一个在t中出现的字符为j的最大长度
void init() //子序列自动机预处理
{
for(int i = m; i >= 1; i --)
{
for(int j = 0; j < 26; j ++)
if(vis[j]) ban[t[i]][j] = 1;
vis[t[i]] = 1;
}
}
int main()
{
scanf("%s", s + 1);
scanf("%s", t + 1);
n = strlen(s + 1);
m = strlen(t + 1);
for(int i = 1; i <= n; i ++) s[i] -= 'a';
for(int i = 1; i <= m; i ++) t[i] -= 'a';
init();
for(int i = 1; i <= n; i ++)
{
for(int j = 0; j < 26; j ++)
f[i][j] = f[i - 1][j] + (vis[s[i]] == 0); //如果s[i]没有在t中出现,可以直接接在后面,且不影响末尾
for(int j = 0; j < 26; j ++)
if(!ban[j][s[i]] && vis[s[i]]) //如果存在这个数,那么不能接在j的后面
f[i][s[i]] = max(f[i][s[i]], f[i - 1][j] + 1);
}
int res = 0;
for(int i = 0; i < 26; i ++)
res = max(res, f[n][i]);
cout << res << '\n';
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】