题号:NC13230
名称:合并回文子串
来源:美团2017年CodeM大赛-初赛A轮

题目链接

时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format:
%lld

题目描述

输入两个字符串A和B,合并成一个串C,属于A和B的字符在C中顺序保持不变。如"abc"和"xyz"可以被组合成"axbycz"或"abxcyz"等。
我们定义字符串的价值为其最长回文子串的长度(回文串表示从正反两边看完全一致的字符串,如"aba"和"xyyx")。
需要求出所有可能的C中价值最大的字符串,输出这个最大价值即可 输入描述:

第一行一个整数T(T ≤ 50)。 接下来2T行,每两行两个字符串分别代表A,B(|A|,|B| ≤ 50),A,B的字符集为全体小写字母。

输出描述:

对于每组数据输出一行一个整数表示价值最大的C的价值。
示例1

输入

2
aa
bb
a
aaaabcaa

输出

4
5

思路:区间dp问题
dp[i][j][m][n]表示A中下标i到j-1以及B中下标m到n-1的串,能否组成回文串
(dp值为零则表示不构成回文串,不为零则表示构成)
首先:字符本身是回文串
其次,分为四种情况
a[i]==a[j-1] dp[i][j][m][n]+=c[i+1][j-1][m][n];
因为dp我们只考虑是否为0或非0,所以dp之间可以+=也可以|=,都不影响
(当A的第i为和第j-1位相同时,那么dp[i][j]是否为回文串就取决于比它小一层的dp[i+1][j-1],这样一次往里推,就可以推到以一种情况)
b[m]==b[n-1] dp[i][j][m][n]+=c[i][j][m+1][n-1];
(和上一个思路相同)

a[i]==b[n-1] dp[i][j][m][n]+=c[i+1][j][m][n-1];
(当A的i与B的n-1相同时,那么dp[i][][][n]是否为回文串就取决于A的后一位i+1和B的前一位n-1的情况)
a[m]==b[j-1] dp[i][j][m][n]+=c[i][j-1][m+1][n];
代码

#include<bits/stdc++.h>
#define maxn 100
using namespace std;
int t;
char a[maxn],b[maxn];
int c[maxn][maxn][maxn][maxn];
int main()
{
    cin>>t;
    char ch=getchar();
    int j;
    int n;
    while(t--)
    {
        int ans=0;
        cin>>a;
        ch=getchar();
        cin>>b;
        ch=getchar();
        int len1=strlen(a),len2=strlen(b);
        for(int tj=0;tj<=len1;tj++)
        {
            for(int tn=0;tn<=len2;tn++)
            {
                for(int i=0;i+tj<=len1;i++)
                {
                    for(int m=0;m+tn<=len2;m++)
                    {
                        j=i+tj;
                        n=m+tn;
                        if(tj+tn<=1)c[i][j][m][n]=1;
                        else
                        {
                            c[i][j][m][n]=0;
                            if(tj>=2&&a[i]==a[j-1])c[i][j][m][n]|=c[i+1][j-1][m][n];                                               
                            if(tn>=2&&b[m]==b[n-1])c[i][j][m][n]|=c[i][j][m+1][n-1];
                            if(tj>=1&&tn>=1&&a[i]==b[n-1])c[i][j][m][n]|=c[i+1][j][m][n-1];
                            if(tj>=1&&tn>=1&&a[m]==b[j-1])c[i][j][m][n]|=c[i][j-1][m+1][n];
                        }
                        if(c[i][j][m][n])ans=max(ans,tj+tn);
                    }
                }
            }
         } 
        cout<<ans<<endl;
    }
    return 0;
}

另外
tj和tn从0开始,用于不断讨论A中i到i+tj和B中m到tn的回文字符串