回文子串 记忆化搜索(DP)

题目大意:给两个串从中选出字母组成回文串,且选出来的字母在新串中的顺序必须与在原串的顺序相等,串长不超过50。

感想:这题看了一下,然后觉得是dp,猜了发转移方程,f[i][j][k][l],表示一串中从前选到i,从后选到k,二串从前选到j,从后选到l,手动模拟了转移过程,发现完全不清楚它怎么配对的,算了,打了个大暴搜回去写线段树去了,昨天写了一天线段树,今天无论如何也要写对,嗯。

分析:以上转移方程其实是对的,恭喜我猜对了,然并卵。现在我算是发现,只要转移不来的,就写记搜,反正我是这么觉得的。记搜的话就简单了,i与k配对,j与l配对,k与j配对,i与l配对,ok。要注意一下奇串和偶串,其实也不难,开始记搜时,奇串从i,j,i+2,j+1,or,i,j,i+1,j+2开始,加2就是为了给中间留个空位,最后答案加1,就得到奇串答案。偶串直接i,j,i+1,j+1开始。

# include <iostream>
# include <cstdio>
# include <cmath>
# include <list>
# include <cstring>
# include <map>
# include <ctime>
# include <algorithm>
# include <queue>
using namespace std;
typedef long long ll;
int read(){
    register int f=1,i=0;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}
    return f*i;
}
const int N=55;
char s[N],t[N];
int f[N][N][N][N],n,m,ans;
inline int DFS(int sl,int tl,int sr,int tr)
{
    if(!sl&&!tl&&sr==n+1&&tr==m+1) return 0;
    if(~f[sl][tl][sr][tr]) return f[sl][tl][sr][tr];
    int tmp=0;
    if(sl&&sr!=n+1&&sl<sr&&s[sl]==s[sr])
        tmp=max(tmp,DFS(sl-1,tl,sr+1,tr)+2);
    if(tl&&tr!=m+1&&tl<tr&&t[tl]==t[tr])
        tmp=max(tmp,DFS(sl,tl-1,sr,tr+1)+2);
    if(sl&&sl!=n+1&&tr&&tr!=m+1&&sl<=sr&&tl<=tr&&s[sl]==t[tr])
        tmp=max(tmp,DFS(sl-1,tl-(tl==tr),sr+(sl==sr),tr+1)+2);
    if(sr&&sr!=n+1&&tl&&tl!=m+1&&sl<=sr&&tl<=tr&&s[sr]==t[tl])
        tmp=max(tmp,DFS(sl-(sl==sr),tl-1,sr+1,tr+(tl==tr))+2);
    return f[sl][tl][sr][tr]=tmp;
}
int main()
{

    scanf("%s%s",s+1,t+1);
    n=strlen(s+1),m=strlen(t+1);
    memset(f,-1,sizeof(f));
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            ans=max(ans,DFS(i,j,i+1,j+1));
            ans=max(ans,DFS(i,j,i+2,j+1)+1);
            ans=max(ans,DFS(i,j,i+1,j+2)+1);
        }
    cout<<ans<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值