牛客竞赛-NC13230

区间DP

在这里插入图片描述
思路:
区间DP
思路:
如果我们用f[i][j][k][l]表示前一个串(a串)的第 i 个字符到第 j 个字符后一个串(b串)的第 k 个字符到第 l 个字符能否组成一个回文串的话,有四种可能,四种当中任意一种为真f[i][j][k][l]就是真。
往 a[i+1] 到 a[j−1] 和 b[k] 到 b[l] 构成的串的两端加上 a[i] 和 a[j] 两个字符:
f[i][j][k][l] |= (f[i+1][j-1][k][l] & (a[i] == a[j]));
往 a[i+1] 到 a[j] 和 b[k] 到 b[l−1] 构成的串的两端加上 a[i] 和 b[l] 两个字符:
f[i][j][k][l] |= (f[i+1][j][k][l-1] & (a[i] == b[l]));
往 a[i] 到 a[j−1] 和 b[k+1] 到 b[l] 构成的串的两端加上 b[k] 和 a[j] 两个字符:
f[i][j][k][l] |= (f[i][j-1][k+1][l] & (b[k] == a[j]));
往 a[i] 到 a[j] 和 b[k+1] 到 b[l−1] 构成的串的两端加上 b[k] 和 b[l] 两个字符:
f[i][j][k][l] |= (f[i][j][k+1][l-1] & (b[k] == b[l]));
问题解决,其实我们可以看到,这个朴素的最长回文子串问题并没有实质上的区别,只是首尾两端加字母的选择从原来的一种变成了2*2种。
若是你没有写过区间dp的话,我提醒一点:区间dp要从短区间扩展到长区间,所以如果你不是使用记忆化搜索的话,就需要按区间长短来枚举而不是直接枚举首末端点!
一个小问题可能出现在边界上:alen+blen<=1时dp[][][][]肯定等于1,这时需要确定dp[][][][]的值肯定>=2,便可以由dp_len=0推出来。边界处理后就是正常的区间的dp啦!
转自:传送门

#pragma GCC optimize(3,"Ofast","inline")  	//G++
#include<bits/stdc++.h>
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fcout cout<<setprecision(4)<<fixed
using namespace std;
typedef long long ll;
//======================================
namespace FastIO{
char print_f[105];void read() {}void print() {putchar('\n');}
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth){x = 0;char ch = getchar();ll f = 1;while (!isdigit(ch)){if (ch == '-')f *= -1;ch = getchar();}while (isdigit(ch)){x = x * 10 + ch - 48;ch = getchar();}x *= f;read(oth...);}
template <typename T, typename... T2>
inline void print(T x, T2... oth){ll p3=-1;if(x<0) putchar('-'),x=-x;do{print_f[++p3] = x%10 + 48;}while(x/=10);while(p3>=0) putchar(print_f[p3--]);putchar(' ');print(oth...);}} // namespace FastIO
using FastIO::print;
using FastIO::read;
//======================================
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn = 1e6+5;
int dp[55][55][55][55];
char a[105],b[105];
int main() {
#ifndef ONLINE_JUDGE
    freopen("H:\\code\\in.in", "r", stdin);
    freopen("H:\\code\\out.out", "w", stdout);
    clock_t c1 = clock();
#endif
//**************************************
    int T;
    read(T);
    while(T--){
        cin>>(a+1)>>(b+1);
        int n=strlen(a+1);
        int m=strlen(b+1);
        int ans=0;
        memset(dp,0,sizeof dp);
        for(int alen=0;alen<=n;alen++)
        for(int blen=0;blen<=m;blen++)
        for(int i=1;i+alen-1<=n;i++){
            int la=i,ra=i+alen-1;
            for(int j=1;j+blen-1<=m;j++){
                int lb=j,rb=j+blen-1;
                if(alen+blen<=1){
                    dp[la][ra][lb][rb]=1;
                }
                else{
                    dp[la][ra][lb][rb]|=dp[la+1][ra-1][lb][rb]&a[la]==a[ra];
                    dp[la][ra][lb][rb]|=dp[la][ra][lb+1][rb-1]&b[lb]==b[rb];
                    dp[la][ra][lb][rb]|=dp[la+1][ra][lb][rb-1]&a[la]==b[rb];
                    dp[la][ra][lb][rb]|=dp[la][ra-1][lb+1][rb]&a[ra]==b[lb];
                }
                if(dp[la][ra][lb][rb]) ans=max(ans,alen+blen);
            }
        }
        print(ans);
    }
//**************************************
    
#ifndef ONLINE_JUDGE
    cerr << "Time:" << clock() - c1 << "ms" << endl;
#endif
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值