[Ybt Advanced 2-2-2] 회문 부분 문자열

回文子 꼬치

주제 링크 : ybt 효율적인 고급 2-2-2

이야기

몇 개의 문자열을 제공하고 각 문자열의 가장 큰 회문 부분 문자열의 길이를 물어보십시오.

아이디어

이를 위해 먼저 회 문의 중심 (열거 형)을 살펴본 다음 길이를 둘로 나눌 수 있습니다.

그러나 하나씩 일치시킬 수는 없으며 시간이 초과되지만 해시를 사용하여 수행 할 수 있습니다.

암호

#include<cstdio>
#include<cstring>
#include<iostream>
#define ull unsigned long long

using namespace std;

int n, l, r, mid, ans, number;
ull times[1000002], zheng[1000002], fan[1000002];
char c[1000002];

int main() {
    
    
	scanf("%s", c + 1);
	n = strlen(c + 1);
	while (n != 3 || c[1] != 'E' || c[2] != 'N' || c[3] != 'D') {
    
    
		number++;
		ans = 1; 
		
		memset(times, 0, sizeof(times));
		memset(zheng, 0, sizeof(zheng));
		memset(fan, 0, sizeof(fan));
		times[0] = 1ull;
		for (int i = 1; i <= n; i++) {
    
    
			times[i] = (times[i - 1] * 131ull);
			zheng[i] = (zheng[i - 1] * 131ull + c[i] - 'a');
		}
		for (int i = n; i >= 1; i--)
			fan[i] = (fan[i + 1] * 131ull + c[i] - 'a');
		
		for (int i = 1; i <= n; i++) {
    
    //枚举重心的位置
			l = 0;
			r = n;
			while (l <= r) {
    
    //长度是奇数
				mid = (l + r) >> 1;
				if (i - mid < 1 || i + mid > n) {
    
    
					r = mid - 1;
					continue;
				}
				if (zheng[i] - zheng[i - mid - 1] * times[mid + 1] == fan[i] - fan[i + mid + 1] * times[mid + 1]) {
    
    
					l = mid + 1;
					ans = max(ans, mid * 2 + 1);
				}
				else {
    
    
					r = mid - 1;
				}
			}
			
			l = 0;
			r = n;
			while (l <= r) {
    
    //长度是偶数
				mid = (l + r) >> 1;
				if (i - mid + 1 < 1 || i + mid > n) {
    
    
					r = mid - 1;
					continue;
				}
				if (zheng[i] - zheng[i - mid] * times[mid] == fan[i + 1] - fan[i + mid + 1] * times[mid]) {
    
    
					l = mid + 1;
					ans = max(ans, mid * 2);
				}
				else {
    
    
					r = mid - 1;
				}
			}
		}
		
		printf("Case %d: %d\n", number, ans);
		
		memset(c, 0, sizeof(c));
		scanf("%s", c + 1);
		n = strlen(c + 1);
	}
	
	return 0;
}

추천

출처blog.csdn.net/weixin_43346722/article/details/112915379