BZOJ2565 最长双回文串

本文介绍了一种解决最长双回文子串问题的方法,通过哈希计算找到字符串中可分割成两个回文串的最长子串。文章提供了一个完整的C++实现示例,并详细解释了算法的三个步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2565

最长双回文串

Description

顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。

输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。

Input

一行由小写英文字母组成的字符串S。

Output

一行一个整数,表示最长双回文子串的长度。

Sample Input

baacaabbacabb

Sample Output

12

HINT

样例说明

从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。

对于100%的数据,2≤|S|≤10^5

2015.4.25新加数据一组

题解

这提题分三步:

用哈希求出以每个串结尾的回文串多长;

枚举分界点尝试拼在一起;

AC A C

代码
#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=2e6+5;
struct sd{
    int lm,mx,rm,sum;
    sd(){lm=mx=rm=sum=-1e9;}
};
sd get(int a,int b,int c,int d){sd x;x.lm=a,x.mx=b,x.rm=c,x.sum=d;return x;}
int lm[M],rm[M],mx[M],sum[M],que[M],n,m;
void in(){scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&que[i]);}
void up(int v){sum[v]=sum[ls]+sum[rs],lm[v]=max(lm[ls],sum[ls]+lm[rs]),rm[v]=max(rm[rs],rm[ls]+sum[rs]),mx[v]=max(max(mx[ls],mx[rs]),rm[ls]+lm[rs]);}
void build(int v,int le,int ri)
{
    if(le==ri){sum[v]=lm[v]=rm[v]=mx[v]=que[le];return;}
    int mid=le+ri>>1;build(ls,le,mid);build(rs,mid+1,ri);up(v);
}
sd ask(int v,int le,int ri,int lb,int rb)
{
    if(lb<=le&&ri<=rb){return get(lm[v],mx[v],rm[v],sum[v]);}
    int mid=le+ri>>1;sd ll,rr,ans;
    if(lb<=mid)ll=ask(ls,le,mid,lb,rb);if(mid<rb)rr=ask(rs,mid+1,ri,lb,rb);
    ans.lm=max(ll.lm,ll.sum+rr.lm),ans.rm=max(rr.rm,ll.rm+rr.sum),ans.mx=max(max(ll.mx,rr.mx),ll.rm+rr.lm);
    return ans;
}
void modify(int v,int le,int ri,int pos,int val)
{
    if(le==ri){mx[v]=lm[v]=rm[v]=sum[v]=val;return;}
    int mid=le+ri>>1;if(pos<=mid)modify(ls,le,mid,pos,val);if(mid<pos)modify(rs,mid+1,ri,pos,val);up(v);
}
void ac()
{
    int op,x,y;build(1,1,n);
    while(m--)
    {
        scanf("%d%d%d",&op,&x,&y);
        if(op==1){if(x>y)swap(x,y);printf("%d\n",ask(1,1,n,x,y).mx);}
        else modify(1,1,n,x,y);
    }
}
int main(){in();ac();}
### BZOJ1461 字符匹配 题解 针对BZOJ1461字符匹配问题,解决方法涉及到了KMP算法以及树状数组的应用。对于此类问题,朴素的算法无法满足时间效率的要求,因为其复杂度可能高达O(ML²),其中M代表模式的数量,L为平均长度[^2]。 为了提高效率,在这个问题中采用了更先进的技术组合——即利用KMP算法来预处理模式,并通过构建失配树(也称为失败指针),使得可以在主上高效地滑动窗口并检测多个模式的存在情况。具体来说: - **前缀函数与KMP准备阶段**:先对每一个给定的模式执行一次KMP算法中的pre_kmp操作,得到各个模式对应的next数组。 - **建立失配树结构**:基于所有模式共同构成的一棵Trie树基础上进一步扩展成带有失配链接指向的AC自动机形式;当遇到某个节点不存在对应字符转移路径时,则沿用该处失配链路直至找到合适的目标或者回到根部重新开始尝试其他分支。 - **查询过程**:遍历整个待查本序列的同时维护当前状态处于哪一层级下的哪个子结点之中,每当成功匹配到完整的单词就更新计数值至相应位置上的f_i变量里去记录下这一事实。 下面是简化版Python代码片段用于说明上述逻辑框架: ```python from collections import defaultdict def build_ac_automaton(patterns): trie = {} fail = [None]*len(patterns) # 构建 Trie 树 for i,pattern in enumerate(patterns): node = trie for char in pattern: if char not in node: node[char]={} node=node[char] node['#']=i queue=[trie] while queue: current=queue.pop() for key,value in list(current.items()): if isinstance(value,int):continue if key=='#': continue parent=current[key] p=fail[current is trie and 0 or id(current)] while True: next_p=p and p.get(key,None) if next_p:break elif p==0: value['fail']=trie break else:p=fail[id(p)] if 'fail'not in value:value['fail']=next_p queue.append(parent) return trie,fail def solve(text, patterns): n=len(text) m=len(patterns) f=[defaultdict(int)for _in range(n)] ac_trie,_=build_ac_automaton(patterns) state=ac_trie for idx,char in enumerate(text+'$',start=-1): while True: trans=state.get(char,state.get('#',{}).get('fail')) if trans!=None: state=trans break elif '#'in state: state[state['#']['fail']] else: state=ac_trie cur_state=state while cur_state!={}and'#'in cur_state: matched_pattern_idx=cur_state['#'] f[idx][matched_pattern_idx]+=1 cur_state=cur_state['fail'] result=[] for i in range(len(f)-1): row=list(f[i].values()) if any(row): result.extend([sum((row[:j+1]))for j,x in enumerate(row[::-1])if x>0]) return sum(result) patterns=["ab","bc"] text="abc" print(solve(text,text)) #[^4] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值