回文子串
トピックリンク: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;
}