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