zoukankan      html  css  js  c++  java
  • Manacher初步

    最长双回文串


    这道题题意就是要找到两个相邻的回文串,使得总长度最长。

    考虑Manacher该过程。该过程我们已经预处理所有以该位置为回文中心的最长回文半径(因为加了‘#’,所以该半径即为实际回文串的长度),一个很明显的想法是:定义(Lp[i])(Rp[i]),分别代表以第(i)位为左端点(右)的最长回文中心。

    于是利用刚刚求过的最长回文半径可以做到这一点。

    不过这显然会漏掉一些情况:一个回文串的子回文串并没有对答案做贡献。换句话言之,有的位置并不是最长回文串的左右端点,但是却是最终答案的分界线。

    于是,我们可以考虑进行递推。一个位置不仅可以有已求出来最长回文串更新,也可以由前一个位置。

    譬如:(Lp[i]=max(Lp[i],Lp[i-1]-1))

    最后统计每一个有‘#’的位置,注意子回文串长度不能为(0)

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cstdio>
    #include<cmath>
    
    #define Re register
    #define CLR(x, y) memset(x,y,sizeof(x)) 
    #define FOR(i, x, y) for(Re int i=x;i<=y;++i)
    #define ROF(i, x, y) for(Re int i=x;i>=y;--i)
    #define SFOR(i, u, v, w) for(Re int i=u;i<=v;i+=w) 
    #define SROF(i, u, v, w) for(Re int i=u;i>=v;i-=w) 
    
    using namespace std;
    
    const int MAXN = 3e5; 
    
    char s[MAXN];
    
    int n, p[MAXN], Lp[MAXN] = {}, Rp[MAXN] = {};
    void Manacher()
    {
    	int mid = 0, maxright = 0, mirror, l, r, d;
    	n = strlen(s);
    	ROF(i, n - 1, 0)
    	{
    		s[i << 1 | 1] = s[i];
    		s[i << 1] = '#';
    	}
    	s[n << 1] = '#';
    	n = n << 1 | 1;
    	s[n] = '~';
    	for(Re int i = 0; i <= n; ++ i)
    	{
    		if(i > maxright)
    		{
    			l = i - 1, r = i + 1;
    			while(r < n && l >= 0 && s[l] == s[r])
    			{
    				++ p[i];
    				-- l, ++ r;
    			}
    			-- r;
    			if(r > maxright) maxright = r, mid = i;
    		}
    		else
    		{
    			mirror = mid * 2 - i, d = maxright - i;
    			if(p[mirror] < d) p[i] = p[mirror];
    			else if(p[mirror] == d)
    			{
    				p[i] = p[mirror];
    				l = i - d - 1, r = i + d + 1;
    				while(l >= 0 && r < n && s[l] == s[r])
    				{
    					++ p[i];
    					-- l, ++ r;
    				}
    				-- r;
    				if(r > maxright) maxright = r, mid = i;
    			}
    			else p[i] = d;
    		}
    	}
    	for(Re int i = 0; i <= n; ++ i)
    	{
    		Lp[i - p[i]] = max(Lp[i - p[i]], p[i]);
    		Rp[i + p[i]] = max(Rp[i + p[i]], p[i]);
    	}
    	return;
    }
    int main()
    {
    	scanf("%s", s);
    	Manacher();
    	for(Re int i = n - 1; i >= 0; -- i) Rp[i] = max(Rp[i], Rp[i + 1] - 1);
    	for(Re int i = 0; i < n; ++ i) Lp[i] = max(Lp[i], Lp[i - 1] - 1);
    	int res = 0;
    	for(int i = 0; i < n; i += 2) 
    	{
    		if(Rp[i] && Lp[i]) res = max(res, Rp[i] + Lp[i]);
    	}	
    	printf("%d
    ", res);
    	return 0;
    }
    
  • 相关阅读:
    正则表达式体会
    checkbox、全选反选,获取值
    弹出窗体值回调
    页面点击任意js事件,触发360、IE浏览器新页面
    XML增、删、改
    面试题
    行列转换
    DataTable 和Json 字符串互转
    前台js与后台方法互调
    文件与base64二进制转换
  • 原文地址:https://www.cnblogs.com/zach20040914/p/14221759.html
Copyright © 2011-2022 走看看