[Ybt Advanced2-2-2]回文部分文字列

回文子串

トピックリンク:ybt効率的な高度な2-2-2

トピック

いくつかの文字列を与えて、各文字列の最大の回文部分文字列の長さを尋ねてください。

アイデア

このために、最初に回文の中心(列挙)を見てから、長さを2つに分割できます。

ただし、1つずつ一致させることはできません。タイムアウトになりますが、ハッシュを使用して一致させることができます。

コード

#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