zoukankan      html  css  js  c++  java
  • [JSOI2016]扭动的回文串


    题解

    可以发现最后的答案一定长成(A)串和(B)串的一对对称的子串(长度可以为(0))
    然后中间夹着(A)串或者(B)串中的一个回文串(长度可以为(0))
    对于每一个中心点,对应的最大的答案中间所夹的那个回文串一定是以这个中心点为对称中心的最长回文串
    那么就从以这个中心点为对称中心的最长回文串的两边开始找那个(A)串和(B)串的对称部分
    看看两边最长能扩展多长,二分+哈希判断即可

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define ull unsigned long long
    const int M = 200010 ;
    const ull Base = 233 ;
    using namespace std ;
    
    char s1[M] , s2[M] , p[M] ;
    ull pw[M] , hsh1[M] , hsh2[M] ;
    int n , m , ans , r[M] , posi[M] ;
    inline bool Same(int l1 , int r1 , int l2 , int r2) {
    	if(l1 > r1) swap(l1 , r1) ; if(l2 > r2) swap(l2 , r2) ;
    	ull tp1 = hsh1[l1] - hsh1[r1 + 1] * pw[r1 - l1 + 1] ;
    	ull tp2 = hsh2[r2] - hsh2[l2 - 1] * pw[r2 - l2 + 1] ;
    	return (tp1 == tp2) ;
    }
    inline void update(int lpos , int rpos , int dlt) {
    	if(dlt < 0) {
    		int l = 1 , r = min(lpos - 1 , n - rpos + 1) , ret = 0 , mid ;
    		while(l <= r) {
    			mid = (l + r) >> 1 ;
    			if(Same(lpos - mid , lpos - 1 , rpos , rpos + mid - 1)) ret = mid , l = mid + 1 ;
    			else r = mid - 1 ;
    		}
    		ans = max(ans , rpos - lpos + 1 + ret * 2) ;
    	}
    	else {
    		int l = 1 , r = min(lpos , n - rpos) , ret = 0 , mid ;
    		while(l <= r) {
    			mid = (l + r) >> 1 ;
    			if(Same(lpos - mid + 1 , lpos , rpos + 1 , rpos + mid)) ret = mid , l = mid + 1 ;
    			else r = mid - 1 ;
    		}
    		ans = max(ans , rpos - lpos + 1 + ret * 2) ;
    	}
    }
    inline void Manacher(char *s , int dlt) {
    	m = 0 ; p[++m] = '$' ;
    	for(int i = 1 ; i <= n ; i ++) {
    		p[++m] = '#' ; posi[m] = i ;
    		p[++m] = s[i] ; posi[m] = i ;
    	}
    	p[++m] = '#' ; posi[m] = n + 1 ; p[++m] = '@' ; 
    	int mx = 0 , pos = 0 ;
    	for(int i = 1 ; i <= m ; i ++) {
    		if(mx > i) r[i] = min(mx - i , r[pos * 2 - i]) ; else r[i] = 1 ;
    		while(p[i - r[i]] == p[i + r[i]]) ++ r[i] ;
    		if(i + r[i] > mx) mx = i + r[i] , pos = i ;
    		update(posi[i - r[i] + 1] , posi[i + r[i] - 1] - 1 , dlt) ;
    	}
    }
    int main() {
    	scanf("%d",&n) ; scanf("%s",s1 + 1) ;  scanf("%s",s2 + 1) ; 
    	pw[0] = 1 ; for(int i = 1 ; i <= n ; i ++) pw[i] = pw[i - 1] * Base ;
    	for(int i = n ; i >= 1 ; i --) hsh1[i] = hsh1[i + 1] * Base + s1[i] ;
    	for(int i = 1 ; i <= n ; i ++) hsh2[i] = hsh2[i - 1] * Base + s2[i] ;
    	Manacher(s1 , -1) ; Manacher(s2 , 1) ;
    	printf("%d
    ",ans) ;
    	return 0 ;
    }
    
  • 相关阅读:
    053467
    053466
    053465
    NC201613 Jelly
    NC14608 after与迷宫
    NC14572 走出迷宫
    340. 通信线路
    1135. 新年好
    903. 昂贵的聘礼
    P5767 [NOI1997]最优乘车
  • 原文地址:https://www.cnblogs.com/beretty/p/10639068.html
Copyright © 2011-2022 走看看