题意:
给定两个字符串a和b,从a和b中选取若干元素,不改变其在原字符串中的顺序,求能够形成的回文串的最大长度。
思路:
区间dp。
用dp[i][j][k][l]表示从a串选取第i个到第j个元素,从b串选取第k个到第l个元素,这些元素能否形成回文串。
可以这样考虑回文串的形成:一个回文串在两边加上相同的字符形成一个新的回文串。
因为要求不改变字符在原串的顺序,所以两边加上的字符有以下几种可能:
a[i]-a[j] a[i]-b[l] b[k]-a[j] b[k]-b[l];
得到以下状态转移方程:
dp[i][j][k][l]|=(a[i]==a[j])&&dp[i+1][j-1][k][l];
dp[i][j][k][l]|=(a[i]==b[l])&&dp[i+1][j][k][l-1];
dp[i][j][k][l]|=(b[k]==a[j])&&dp[i][j-1][k+1][l];
dp[i][j][k][l]|=(b[k]==b[l])&&dp[i][j][k+1][l-1];
对于边界的处理:只要两个串选择的字符个数为1,dp就为1。
区间dp要从短区间扩展到长区间,所以要枚举区间的长度而不是首末端点。
代码:

#include <iostream>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <functional>
#include <string>
#include <cstring>
#include <sstream>
#include <deque>
using namespace std;

typedef long long ll;
typedef pair<int,int> P;
typedef pair<int,P> Q;
const int inf=2e9+9;
const int maxn=1e6+9;
const int maxx=2e5+9;

char a[55],b[55];
int dp[55][55][55][55];

int main()
{
    int t; cin>>t;
    while(t--)
    {
        cin>>a+1>>b+1;
        memset(dp,0,sizeof dp);
        int l1=strlen(a+1),l2=strlen(b+1);
        int res=0;
        for(int len1=0;len1<=l1;len1++)
        for(int len2=0;len2<=l2;len2++)
        for(int i=1;i+len1-1<=l1;i++)
        for(int k=1;k+len2-1<=l2;k++)
        {
            int j=i+len1-1,l=k+len2-1;
            if(j+l-k-i+2<=1) dp[i][j][k][l]=1;
            else
            {
                dp[i][j][k][l]|=(a[i]==a[j])&&dp[i+1][j-1][k][l];
                dp[i][j][k][l]|=(a[i]==b[l])&&dp[i+1][j][k][l-1];
                dp[i][j][k][l]|=(b[k]==a[j])&&dp[i][j-1][k+1][l];
                dp[i][j][k][l]|=(b[k]==b[l])&&dp[i][j][k+1][l-1];
            }
            if(dp[i][j][k][l]) res=max(res,len1+len2);
        }
        cout<<res<<endl;
    }
}