https://www.acwing.com/problem/content/141/
哈希做法:
对于每个回文串,长度要么是奇数,要么是偶数
如果长度为奇数,那么枚举中间点,二分长度,用哈希判断左右字串是否相等
如果为偶数,则枚举中间空格
预处理出前缀和后缀字串的哈希值,则可以在(O(1))时间内求出任何字串的哈希值
Manacher:
Manacher算法的核心思想就是维护每个位置的回文半径(p[i]),然后维护前面已经
处理过的位置中,回文半径扩展到的最右端的位置 (r) ,和扩展到 (r) 位置的回文串中心位置 (mid),
于是对当前位置,如果当前位置在(r)的范围之内,则可以先将答案更新成对称位置处的长度,
然后再暴力扩展。 所有位置暴力扩展的长度之和是(n),所以Manacher是线性做法
哈希+二分:时间复杂度(O(nlogn))
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 1000010;
const int M = 1000000007;
int n, ans;
int base = 131;
int Hash_pre[maxn], Hash_suf[maxn], P[maxn];
char s[maxn];
bool Check_odd(int x, int pos){
if(pos <= x || pos + x > n) return false;
int Hl = (Hash_pre[pos - 1] - 1ll * Hash_pre[pos - x - 1] * P[x] % M + M) % M;
int Hr = (Hash_suf[pos + 1] - 1ll * Hash_suf[pos + x + 1] * P[x] % M + M) % M;
if(Hl == Hr) return true;
else return false;
}
bool Check_even(int x, int pos){
if(pos < x || pos + x > n) return false;
int Hl = (Hash_pre[pos] - 1ll * Hash_pre[pos - x] * P[x] % M + M) % M;
int Hr = (Hash_suf[pos + 1] - 1ll * Hash_suf[pos + x + 1] * P[x] % M + M) % M;
if(Hl == Hr) return true;
else return false;
}
void erf(int pos){
int res = 0;
// odd erf
int L = 0, R = n;
while(L < R){
int Mid = (L + R + 1) >> 1;
if(Check_odd(Mid, pos)){
L = Mid;
} else {
R = Mid - 1;
}
}
res = L;
ans = max(ans, res * 2 + 1);
// even erf
L = 0, R = n;
while(L < R){
int Mid = (L + R + 1) >> 1;
if(Check_even(Mid, pos)){
L = Mid;
} else{
R = Mid - 1;
}
}
res = L;
ans = max(ans, res * 2);
}
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
int Case = 0;
while(scanf("%s",s+1) && s[1] != 'E'){
ans = 0;
n = strlen(s+1);
P[0] = 1;
for(int i=1;i<=n;++i){
Hash_pre[i] = (1ll * Hash_pre[i-1] * base % M + (s[i] - 'a' + 1)) % M;
P[i] = 1ll * P[i-1] * base % M;
}
for(int i=n;i>=1;--i)
Hash_suf[i] = (1ll * Hash_suf[i+1] * base % M + (s[i] - 'a' + 1)) % M;
for(int i=1;i<=n;++i){
erf(i);
}
printf("Case %d: %d
", ++Case, ans);
}
return 0;
}
Manacher:(O(n))
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 2200010;
int n, len, ans;
int p[maxn], mid, r;
char s[maxn],ss[maxn];
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
int Case = 0;
while(scanf("%s",s+1) && s[1] != 'E'){
len = 0; mid = 0, r = 0; ans = 0;
memset(p, 0 , sizeof(p));
n = strlen(s+1);
ss[0] = '~';
for(int i=1;i<=n;++i){
ss[++len] = '#';
ss[++len] = s[i];
}
ss[++len] = '#';
for(int i=0;i<=len;++i) s[i] = ss[i];
for(int i=1;i<=len;++i){
if(i <= r) p[i] = min(p[mid * 2 - i], r - i + 1);
while(s[p[i] + i] == s[i - p[i]]) ++p[i];
if(p[i] + i - 1 > r){
r = p[i] + i - 1, mid = i;
}
ans = max(ans, p[i] - 1);
}
printf("Case %d: %d
",++Case,ans);
}
return 0;
}