zoukankan      html  css  js  c++  java
  • AcWing 139 回文子串的最大长度 (哈希+二分 / Manacher)

    https://www.acwing.com/problem/content/141/

    哈希做法:
    对于每个回文串,长度要么是奇数,要么是偶数
    如果长度为奇数,那么枚举中间点,二分长度,用哈希判断左右字串是否相等
    如果为偶数,则枚举中间空格

    预处理出前缀和后缀字串的哈希值,则可以在(O(1))时间内求出任何字串的哈希值

    Manacher:
    Manacher算法的核心思想就是维护每个位置的回文半径(p[i]),然后维护前面已经
    处理过的位置中,回文半径扩展到的最右端的位置 (r) ,和扩展到 (r) 位置的回文串中心位置 (mid),

    于是对当前位置,如果当前位置在(r)的范围之内,则可以先将答案更新成对称位置处的长度,
    然后再暴力扩展。 所有位置暴力扩展的长度之和是(n),所以Manacher是线性做法

    哈希+二分:时间复杂度(O(nlogn))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 1000010;
    const int M = 1000000007;
    
    int n, ans;
    int base = 131;
    int Hash_pre[maxn], Hash_suf[maxn], P[maxn];
    char s[maxn];
    
    bool Check_odd(int x, int pos){
    	if(pos <= x || pos + x > n) return false;
    	
    	int Hl = (Hash_pre[pos - 1] - 1ll * Hash_pre[pos - x - 1] * P[x] % M + M) % M;
    	int Hr = (Hash_suf[pos + 1] - 1ll * Hash_suf[pos + x + 1] * P[x] % M + M) % M;
    	
    	if(Hl == Hr) return true;
    	else return false;
    }
    
    bool Check_even(int x, int pos){
    	if(pos < x || pos + x > n) return false;
    	
    	int Hl = (Hash_pre[pos] - 1ll * Hash_pre[pos - x] * P[x] % M + M) % M;
    	int Hr = (Hash_suf[pos + 1] - 1ll * Hash_suf[pos + x + 1] * P[x] % M + M) % M;
    	
    	if(Hl == Hr) return true;
    	else return false;
    }
    
    void erf(int pos){
    	int res = 0;
    	// odd erf
    	int L = 0, R = n;
    	while(L < R){
    		int Mid = (L + R + 1) >> 1;
    		if(Check_odd(Mid, pos)){
    			L = Mid;
    		} else {
    			R = Mid - 1;
    		}
    	}
    	res = L;
    	ans = max(ans, res * 2 + 1);
    	// even erf
    	
    	L = 0, R = n;
    	while(L < R){
    		int Mid = (L + R + 1) >> 1;
    		if(Check_even(Mid, pos)){
    			L = Mid;
    		} else{
    			R = Mid - 1;
    		}
    	}
    	res = L;
    	ans = max(ans, res * 2);
    } 
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	int Case = 0;
    	while(scanf("%s",s+1) && s[1] != 'E'){
    		ans = 0;
    		n = strlen(s+1);
    		
    		P[0] = 1;
    		for(int i=1;i<=n;++i){
    			Hash_pre[i] = (1ll * Hash_pre[i-1] * base % M + (s[i] - 'a' + 1)) % M;
    			P[i] = 1ll * P[i-1] * base % M;
    		}
    			
    		for(int i=n;i>=1;--i)
    			Hash_suf[i] = (1ll * Hash_suf[i+1] * base % M + (s[i] - 'a' + 1)) % M;
    		
    		for(int i=1;i<=n;++i){
    			erf(i);	
    		}
    		
    		printf("Case %d: %d
    ", ++Case, ans);
    	}
    	return 0;
    }
    

    Manacher:(O(n))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 2200010;
    
    int n, len, ans;
    int p[maxn], mid, r;
    char s[maxn],ss[maxn];
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	int Case = 0;
    	while(scanf("%s",s+1) && s[1] != 'E'){
    		len = 0; mid = 0, r = 0; ans = 0;
    		memset(p, 0 , sizeof(p));
    		n = strlen(s+1);
    		
    		ss[0] = '~';
    		for(int i=1;i<=n;++i){
    			ss[++len] = '#';
    			ss[++len] = s[i];
    		}
    		ss[++len] = '#';
    		for(int i=0;i<=len;++i) s[i] = ss[i];
    		
    		for(int i=1;i<=len;++i){
    			if(i <= r) p[i] = min(p[mid * 2 - i], r - i + 1);
    			
    			while(s[p[i] + i] == s[i - p[i]]) ++p[i];
    			
    			if(p[i] + i - 1 > r){
    				r = p[i] + i - 1, mid = i;
    			}
    			ans = max(ans, p[i] - 1);
    		}
    		
    		printf("Case %d: %d
    ",++Case,ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    linux 内存映射-ioremap和mmap函数
    vue 模板语法-插值的操作(12-22)
    chrome浏览器json插件
    vue初识(1-11)2020-10-27
    后盾人:JS课程第一章(11-18)2020-10-25
    博客园美化
    chrome 设置自动刷新网页
    二叉树的层次遍历
    poj 2905 双向队列(待补充)
    poj 2159 D
  • 原文地址:https://www.cnblogs.com/tuchen/p/13940484.html
Copyright © 2011-2022 走看看