NC 13230 区间 DP

题意

传送门 NC 13230

题解

对于单串最长回文子串的长度,一种解法为二维 D P DP DP d p [ i ] [ j ] dp[i][j] dp[i][j] 代表字符串区间 [ i , j ) [i,j) [i,j) 的最长回文子串长度,由于单串区间长度的增加只有向左右界移动的可能;考虑到回文子串对称的字符的位置有在区间两端,或不在两端,或一个在区间内而另一个在区间端点三种可能;则有递推式
d p [ i ] [ j ] = { d p [ i + 1 ] [ j − 1 ] + 1 s t r [ i ] = s t r [ j − 1 ] m a x ( d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] ) o t h e r w i s e dp[i][j]=\begin{cases} dp[i+1][j-1] + 1 & str[i]=str[j-1]\\ max(dp[i+1][j], dp[i][j-1]) & otherwise\\ \end{cases} dp[i][j]={dp[i+1][j1]+1max(dp[i+1][j],dp[i][j1])str[i]=str[j1]otherwise 本题涉及 2 2 2 个字符串,求合并的回文子串长度。此时区间的增加,对于左界或右界而言都有 2 2 2 种可能,如果仍然使用子串的转移方程则需要写出 2 × 2 × 3 2\times 2 \times 3 2×2×3 个可能的状态转移。为了编程简单,改变 D P DP DP 的定义, d p [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] dp[x1][y1][x2][y2] dp[x1][y1][x2][y2] 代表两个字符串 a , b a,b a,b 分别在 [ x 1 , y 1 ) , [ x 2 , y 2 ) [x1,y1),[x2,y2) [x1,y1),[x2,y2) 的合并是否是回文串,此时需要在状态的遍历中更新答案
d p [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ]   ∣ = { d p [ x 1 + 1 ] [ y 1 ] [ x 2 ] [ y 2 − 1 ] x 1 < y 1 & x 2 < y 2 & a [ x 1 ] = b [ y 2 − 1 ] d p [ x 1 + 1 ] [ y 1 − 1 ] [ x 2 ] [ y 2 ] x 1 + 1 < y 1 & x 2 < = y 2 & a [ x 1 ] = a [ y 1 − 1 ] d p [ x 1 ] [ y 1 − 1 ] [ x 2 + 1 ] [ y 2 ] x 1 < y 1 & x 2 < y 2 & a [ y 1 − 1 ] = b [ x 2 ] d p [ x 1 ] [ y 1 ] [ x 2 + 1 ] [ y 2 − 1 ] x 1 < = y 1 & x 2 + 1 < y 2 & b [ x 2 ] = b [ y 2 − 1 ] dp[x1][y1][x2][y2]\ |=\begin{cases} dp[x1 + 1][y1][x2][y2 - 1] & x1 < y1 \& x2 < y2\&a[x1] = b[y2 - 1] \\ dp[x1 + 1][y1 - 1][x2][y2] & x1 + 1 < y1 \& x2 <= y2 \& a[x1] = a[y1 - 1] \\ dp[x1][y1 - 1][x2 + 1][y2] & x1 < y1 \& x2 < y2 \& a[y1 - 1] = b[x2] \\ dp[x1][y1][x2 + 1][y2 - 1] & x1 <= y1 \& x2 + 1 < y2 \& b[x2] = b[y2 - 1] \\ \end{cases} dp[x1][y1][x2][y2] =dp[x1+1][y1][x2][y21]dp[x1+1][y11][x2][y2]dp[x1][y11][x2+1][y2]dp[x1][y1][x2+1][y21]x1<y1&x2<y2&a[x1]=b[y21]x1+1<y1&x2<=y2&a[x1]=a[y11]x1<y1&x2<y2&a[y11]=b[x2]x1<=y1&x2+1<y2&b[x2]=b[y21]

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 55
bool dp[maxn][maxn][maxn][maxn];
char a[maxn], b[maxn];

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf(" %s%s", a, b);
        memset(dp, 0, sizeof(dp));
        int n1 = strlen(a), n2 = strlen(b), res = 0;
        for (int w1 = 0; w1 <= n1; w1++)
        {
            for (int x1 = 0; x1 + w1 <= n1; x1++)
            {
                for (int w2 = 0; w2 <= n2; w2++)
                {
                    for (int x2 = 0; x2 + w2 <= n2; x2++)
                    {
                        int y1 = x1 + w1, y2 = x2 + w2, len = w1 + w2, f = 0;
                        if (w1 + w2 <= 1)
                        {
                            f = 1;
                        }
                        if (x1 < y1 && x2 < y2 && a[x1] == b[y2 - 1])
                        {
                            f |= dp[x1 + 1][y1][x2][y2 - 1];
                        }
                        if (x1 + 1 < y1 && x2 <= y2 && a[x1] == a[y1 - 1])
                        {
                            f |= dp[x1 + 1][y1 - 1][x2][y2];
                        }
                        if (x1 < y1 && x2 < y2 && a[y1 - 1] == b[x2])
                        {
                            f |= dp[x1][y1 - 1][x2 + 1][y2];
                        }
                        if (x1 <= y1 && x2 + 1 < y2 && b[x2] == b[y2 - 1])
                        {
                            f |= dp[x1][y1][x2 + 1][y2 - 1];
                        }
                        if (f)
                        {
                            dp[x1][y1][x2][y2] = f;
                            res = max(res, len);
                        }
                    }
                }
            }
        }
        printf("%d\n", res);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值