【YbtOJ#20235】公共序列

题目

题目链接:https://www.ybtoj.com.cn/contest/66/problem/3

\(|A|\leq 10^6,|B|\leq 10^3\)

思路

直接设 \(f[i][j]\) 表示两个串分别匹配到第 \(i,j\) 位的方法已经行不通了。但是因为 \(|B|\leq 10^3\),所以可以在这里考虑一下。
\(f[i][j]\) 表示 \(B\) 串前 \(i\) 位匹配了其中 \(j\) 位,在 \(A\) 串中至少要匹配掉前多少位。
那么假设 \(B[i]\)\(f[i-1][j-1]\) 后面下一个可以匹配到的位置是 \(k\),显然

\[f[i][j]\min(f[i-1][j],k) \]

然后在所有 \(f[i][j]<+\infty\) 中取 \(j\) 的最大值即可。
时间复杂度 \(O(n^2\log m)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=1010,M=1000010;
int n,m,ans,f[N][N];
char s[N],t[M];
vector<int> pos[27];

int main()
{
	freopen("lcs.in","r",stdin);
	freopen("lcs.out","w",stdout);
	scanf("%s%s",t+1,s+1);
	n=strlen(s+1); m=strlen(t+1);
	for (int i=1;i<=m;i++)
		pos[t[i]-'a'+1].push_back(i);
	for (int i=1;i<=26;i++)
		pos[i].push_back(2e9);
	memset(f,0x3f3f3f3f,sizeof(f));
	f[0][0]=0;
	for (int i=1;i<=n;i++)
		for (int j=0;j<=i;j++)
		{
			int k=*upper_bound(pos[s[i]-'a'+1].begin(),pos[s[i]-'a'+1].end(),f[i-1][j-1]);
			f[i][j]=min(f[i-1][j],k);
			if (f[i][j]<=m) ans=max(ans,j);
		}
	printf("%d",ans);
	return 0;
}
posted @ 2020-12-01 15:10  stoorz  阅读(73)  评论(0编辑  收藏  举报