正题
题目链接:https://www.ybtoj.com.cn/contest/66/problem/3
题目大意
给出两个字符串A,BA,BA,B,求它们的最长公共子序列。
解题思路
先考虑朴素的dpdpdp,设fi,jf_{i,j}fi,j表示到AAA的第iii个,BBB的第jjj个时候的最长公共子序列长度。
发现这样的dpdpdp由于A的长度很大,B的长度很小,所以导致dpdpdp里的数值很小,转移却十分冗长。发现还有一种最优的状态表示法,当匹配到BBB的相同位置且当且公共长度相同时显然在AAA的位置越前越好。那么可以设fi,jf_{i,j}fi,j表示匹配到BBB的第iii个时,目前公共长度为jjj的在AAA中最前的位置。
时间复杂度O(26n+m2)O(26n+m^2)O(26n+m2)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10,M=1100;
int n,m,last[26],nxt[N][26],f[M][M];
char a[N],b[M];
int main()
{freopen("lcs.in","r",stdin);freopen("lcs.out","w",stdout);scanf("%s",a+1);n=strlen(a+1);scanf("%s",b+1);m=strlen(b+1);for(int i=n;i>=0;i--){for(int j=0;j<26;j++)nxt[i][j]=last[j];if(i)last[a[i]-'a']=i;}memset(f,0x3f,sizeof(f));f[0][0]=0;for(int i=1;i<=m;i++){for(int j=0;j<=i;j++){if(j&&f[i-1][j-1]<=n&&nxt[f[i-1][j-1]][b[i]-'a'])f[i][j]=min(f[i][j],nxt[f[i-1][j-1]][b[i]-'a']);f[i][j]=min(f[i][j],f[i-1][j]);}}for(int i=m;i>=0;i--)if(f[m][i]<2147483647/3)return printf("%d\n",i);return 0;
}