【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;
}
posted @ 2016-11-21 18:54  sadstone  阅读(75)  评论(0编辑  收藏  举报