BZOJ2565

BZOJ2565
  • 题目

    BZOJ2565

  • 分析

    前置知识: m a n a c h e r manacher manacher

    要知道 m a n a c h e r manacher manacher 的性质:插完无关字符后得到的回文路径数组 h w [ i ] hw[i] hw[i] ,可以通过这个数组得到原字符串当前位置下的最长回文路径即: h w [ i ] − 1 hw[i] - 1 hw[i]1。这个可以自己模拟模拟
    假设 m a n a c h e r manacher manacher 已经写好, h w [ i ] hw[i] hw[i] 数组已经得出,题目要求两个相邻回文串相连的最大长度,相邻而又不能重复,这提示可以在插入的无关字符串位置上更新答案,这个位置是两个相邻回文串的边界,左边是前一个回文串结束的位置,右边是后一个回文串开始的位置,又要求左右相加最长,那么问题转化为当前位置 i   ( s [ i ] = = ′ # ′ ) i \,(s[i] == '\#') i(s[i]==#) , 找到以当前点结束最长的回文串长度 l l l 和以当前点开始的回文串最长的长度 r r r , l + r l + r l+r,即是这个点的答案,全局的答案是遍历所有的无关字符的位置。。遍历已经是 O ( n ) O(n) O(n) 的,所以要预处理 l l l r r r.
    设数组 l [ i ] l[i] l[i] 表示 以 i i i 点为结尾的最长的回文串长度, r [ i ] r[i] r[i] 表示以 i i i 点为开始的最长回文串长度。可以在跑回文串的过程中更新 l , r l,r l,r 数组。 l [ i + h w [ i ] − 1 ] = m a x ( l [ i + h w [ i ] − 1 ] , h w [ i ] − 1 ] ) l[i + hw[i] - 1] = max(l[i + hw[i] - 1],hw[i] - 1]) l[i+hw[i]1]=max(l[i+hw[i]1],hw[i]1]) ,这里用到之前说的性质,在 i + h w [ i ] − 1 i + hw[i] - 1 i+hw[i]1 位置结束的是当前回文串,更新回文串的长度 h w [ i ] − 1 hw[i] - 1 hw[i]1.
    处理好之后,还要处理一些不是最长的回文串位置上的 l [ i ] , r [ i ] l[i],r[i] l[i],r[i] 。如 # a # a # a # a # a # \#a\#a\#a\#a\#a\# #a#a#a#a#a# 最后 # \# # 的会被更新,但是中间的 # \# # 点上的 r [ i ] , l [ i ] r[i],l[i] r[i],l[i] 不一定会被更新,因为之前求的是最长回文串,所以像 a a a aaa aaa 这种不饱和回文串就不会被更新,因为每从一个 # \# # 移到下一个 # \# # 都会移两格,所以都是 − 2 -2 2

  • 代码

    const int N = 2e5 + 5;
    char a[N], s[N];
    int hw[N], l[N], r[N];
    int mid, rx, tot;
    int main ()
    {
    	//freopen("input.in", "r", stdin);
    	//freopen("test.out", "w", stdout);
    	scanf("%s", a);
    	int n = strlen(a);
    	s[++tot] = '$';
    	s[++tot] = '#';
    	for (int i = 0; i < n; i++)
    	{
    		s[++tot] = a[i];
    		s[++tot] = '#';
    	}
    	s[++tot] = '\0';
    	for (int i = 1; i <= tot; i++)
    	{
    		hw[i] = i < rx ? min(hw[(mid << 1) - i], rx - i) : 1;
    		while (s[i + hw[i]] == s[i - hw[i]])
    			hw[i] ++;
    		if (i + hw[i] > rx)
    		{
    			rx = i + hw[i];
    			mid = i;
    		}
    		l[i + hw[i] - 1] = max(l[i + hw[i] - 1], hw[i] - 1);
    		r[i - hw[i] + 1] = max(r[i - hw[i] + 1], hw[i] - 1);
    	}
    	for (int i = 2; i <= tot; i += 2) r[i] = max(r[i], r[i - 2] - 2);
    	for (int i = tot; i >= 2; i -= 2) l[i] = max(l[i], l[i + 2] - 2);
        int ans = 0;
    	for(int i = 2;i <= tot;i += 2) if(r[i] && l[i]) ans = max(ans,l[i] + r[i]);
    	printf("%d\n", ans);
    	return 0 ;
    }
    
  • 题型

    回文串

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值