题目大意
求两个字符串的最长公共回文子序列。
其中一个字符串长度仅为20。
SB题
用2^20枚举最长公共回文子序列,然后检验很长的那个串是否存在这个子序列。
可以预处理next[i,j]表示第i个位置后的第一个字符为j的位置,这样每次检验只跳m步。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100000+10,maxm=20+10;
char a[maxn],b[maxm],s[maxm];
int next[maxn][26];
bool bz[maxm];
int i,j,k,l,t,n,m,ans,len;
bool check(){
int i;
len=0;
fo(i,1,m)
if (bz[i]) s[++len]=b[i];
fo(i,1,len/2)
if (s[i]!=s[len-i+1]) return 0;
return 1;
}
bool find(){
int i,j=0;
fo(i,1,len){
j=next[j][s[i]-'a'];
if (j>n) return 0;
}
return 1;
}
void dfs(int x,int y){
if (y+m-x+1<=ans) return;
if (x==m+1){
if (!check()||!find()) return;
ans=y;
return;
}
bz[x]=1;
dfs(x+1,y+1);
bz[x]=0;
dfs(x+1,y);
}
int main(){
freopen("lcps.in","r",stdin);freopen("lcps.out","w",stdout);
scanf("%s",a+1);
n=strlen(a+1);
fo(i,0,25) next[n][i]=n+1;
fd(i,n-1,0){
fo(j,0,25) next[i][j]=next[i+1][j];
next[i][a[i+1]-'a']=i+1;
}
scanf("%s",b+1);
m=strlen(b+1);
ans=0;
dfs(1,0);
printf("%d\n",ans);
}