题目链接:https://ac.nowcoder.com/acm/contest/1008/C
题面:
思路:先对字符串进行正向哈希和反向哈希,然后枚举间断点
分两种情况讨论
1,回文序列为奇数时,枚举点为中间点
2,回文序列为偶数时,枚举点为中间间隔
在这里主要想讲一下二分
首先我们要先确定对什么进行二分,有两种思路
1)对回文串的起点进行二分(我们枚举的点为中点)
2)对回文串的一半长度进行二分
如果我们对回文串的起点进行二分,那么我们枚举点超过所给字符串的一半时,对二分的参数要进行多个改变,l, r都要改变;最后计算长度的公式也要改变;
所以我们选择对回文串一半的长度进行二分
然后我们确定如何二分,即二分的结果是什么?我们可以知道,二分的结果是在满足为回文序列的情况下,找到最大的回文长度。
所以在二分过程中,我们的边界的更新应该这样的
int mid = (l + r + 1) >> 1; //find the most
if(t1 == t2) l = mid;
else r = mid - 1;
最后则是注意一些特殊情况,回文序列为偶数时,我们枚举的是中间间隔,所以二分区间也要变为
r = min(i, len - i);
t2 = calcu(i, 0, r, 1); m2 = max(m2, t2);
还有就是h2[len + 1] = 0; 防止在更新h2中的点的哈希值时,受上一个case的影响
具体参考代码实现
AC代码
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstring>
#include <string>
#include <cmath>
#include <iomanip>
#include <stdlib.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#define Pi acos(-1.0)
#define Mid ll + ((rr - ll) >> 1)
#define Lson p << 1, ll, Mid
#define Rson p << 1 | 1, Mid + 1, rr
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int P = 131, N = 1e6 + 5;
char s[N];
ULL h1[N], h2[N], p[N];
int t, m1, m2, len;
int calcu(int id, int l, int r, bool f){
while(l < r){
int mid = (l + r + 1) >> 1; //find the most
ULL t1, t2;
if(!f){
t1 = h1[id - 1] - h1[id - mid - 1] * p[mid];
t2 = h2[id + 1] - h2[id + mid + 1] * p[mid];
}
else{
t1 = h1[id] - h1[id - mid] * p[mid];
t2 = h2[id + 1] - h2[id + mid + 1] * p[mid];
}
if(t1 == t2) l = mid;
else r = mid - 1;
}
return f ? l * 2 : l * 2 + 1;
}
int main(){
p[0] = 1;
for(int i = 1; i < N; ++i){
p[i] = p[i - 1] * P;
}
while(1){
scanf("%s", s + 1);
if(strcmp(s + 1, "END") == 0) break;
m1 = 0; m2 = 0;
len = strlen(s + 1);
h2[len + 1] = 0;
for(int i = 1; i <= len; ++i){
h1[i] = h1[i - 1] * P + (s[i] - 'a' + 1);
h2[len - i + 1] = h2[len - i + 2] * P + (s[len - i + 1] - 'a' + 1);
}
for(int i = 1; i <= len; ++i){
int t1, t2, r;
r = min(i - 1, len - i);
t1 = calcu(i, 0, r, 0); m1 = max(m1, t1);
r = min(i, len - i);
t2 = calcu(i, 0, r, 1); m2 = max(m2, t2);
//printf("t1 : %d, t2 : %d, m1 : %d, m2 : %d\n", t1, t2, m1, m2);
}
printf("Case %d: %d\n", ++t, max(m1, m2));
}
//system("pause");
return 0;
}