回文子 꼬치
주제 링크 : 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;
}