【JZOJ4889】最长公共回文子序列
Description
给一个长度为n(1≤n≤100000)的字符串a和一个长度为m(1≤m≤20)的字符串b,求a和b的最长公共回文子序列的长度。
Solution
m很小,于是我们可以枚举回文子序列。
对于字符串a,对于每个位置的向下一个’a’~’z’的位置连一条边,这可以O(n)处理。
对于枚举出来的回文子序列c,我们用以上的预处理可以O(m)判断是否在a中出现。
时间复杂度: O(2mm)
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define ll long long
#define N 100100
#define M 21
#define inf 2147483647
using namespace std;
char a[N],b[M],c[M];
int nx[N][26];
int l1,l2;
int ls[26];
int ans=0;
void dfs(int x,int t)
{
if(t+l2-x+1<=ans) return;
if(x>l2)
{
fo(i,1,t/2)
if(c[i]!=c[t-i+1]) return;
int p=0;
int z=0;
fo(i,1,t)
{
p=nx[p][c[i]-'a'];
if(!p) break;
z++;
}
if(z==t && ans<t) ans=t;
return;
}
c[t+1]=b[x];
dfs(x+1,t+1);
dfs(x+1,t);
}
int main()
{
freopen("lcps.in","r",stdin);
freopen("lcps.out","w",stdout);
scanf("%s",a+1);l1=strlen(a+1);
scanf("%s",b+1);l2=strlen(b+1);
fd(i,l1,1)
{
fo(j,0,25) nx[i-1][j]=nx[i][j];
int t=a[i]-'a';
nx[i-1][t]=i;
}
dfs(1,0);
cout<<ans;
}