题号: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的回文字符串