求给定字符串的最长回文子序列。
f[i][j]表示前i个字符已经处理到长度为j的回文子串的最右位置(为最大化答案)。
g[i][j]表示前i个字符中离i最近的字符j的位置。
有f[i][j]=max(f[i-1][j], p[f[i-1][j-2]-1][str[i]])
一种是继承前i-1字符的结果,另一种是令str[i]为当前回文子串的结尾,结果为找到f[i-1][j-2]的左端前和str[i]相等的字符。
然后f[n][t]中最大的t有解的为结果。
输出答案按照dp方程找即可。
当前查询前t个字符的话,找上一个字符的范围就是1..p[t][str[f[t][k]]]-1.
神TM数组开小了f答案全乱了。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int N = 50005;
char str[N]={0}, ans[N];
int p[N][26], f[N][101]={0};
int main() {
int n, i, j, k, l = 0, t;
scanf("%s", str+1);
t = n = strlen(str+1);
FOR(i,1,n) str[i]-='a';
FOR(i,1,n) memcpy(p[i],p[i-1],sizeof(p[0])),p[i][str[i]]=i;
FOR(i,1,n) f[i][0]=i+1,f[i][1]=i;
FOR(i,2,n) FOR(j,2,100)
f[i][j]=max(f[i][j],(f[i-1][j-2])?(<span style="font-family: Arial, Helvetica, sans-serif;">p[f[i-1][j-2]-1][str[i]]):(f[i-1][j]));</span>
FOR(i,0,100) if(f[n][i]) k=i;
while (k > 1) {
ans[l++]=str[f[t][k]]+'a';
t=p[t][str[f[t][k]]]-1;
k-=2;
}
ans[l]=0;
printf("%s", ans);
if(k)printf("%c",str[f[t][k]]+'a');
reverse(ans, ans+l);
printf("%s", ans);
return 0;
}