最长回文 hdu 3068 poj 3974 ural 1297
http://acm.hdu.edu.cn/showproblem.php?pid=3068
http://poj.org/problem?id=3974
http://acm.timus.ru/problem.aspx?space=1&num=1297
题意:给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
思路:
1、Manacher解法,再每个字母前后面插入字符'#',再找最长回文串。
2、拓展KMP解法
3、后缀数组解法(超时了)
4、二分+暴力(水过)
解法4:(三个题目都可以这样解)明显,如果回文的长度是L,那么答案一定不小于L,因而能够二分答案。在判断L是否满足的时候,可以这样做:
sum[a]是前a个字符串和;
如果L是偶数,且sum[a]-sum[a-L/2]=sum[L/2+a] - sum[a],则开始进行回文匹配。
如果L是奇数,且sum[a-1]-sum[a-L/2-1]=sum[L/2+a]-sum[a];则开始进行回文匹配。
二分的时候先进行奇性匹配,因为L+1>L;如果成功则返回。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") #define NU(x) (x[0]*1000+x[1]*100+x[2]*10+x[3]) using namespace std; const int maxn = 110005; int as[maxn],L,flag; char str[maxn]; int judge(int g) { int i,k = 0; for(i = g; i + g <= L; ++ i) { if(i-g){ if(as[i-1]-as[i-g-1]==as[i+g]-as[i]){ k = g; int s = i - 1; int t = i + 1; while(k){ if(str[s-1]^str[t-1])break; s--; t++; k--; } if(!k){flag = 1; return 1;} } } } for(i = g; i + g <= L; ++ i) { if(as[i]-as[i-g]==as[i+g]-as[i]){ k = g; int s = i; int t = i + 1; while(k){ if(str[s-1]^str[t-1])break; s--; t++; k--; } if(!k){flag = 0; return 1;} } } return 0; } int main() { int i,low,high,mid,ans; while(scanf("%s",str)==1){ L = strlen(str); as[1] = str[0]; for(i = 1; i < L; ++ i) as[i+1] = as[i] + str[i]; low = 1; high = L / 2; ans = 1; while(low<=high){ mid = (low + high) >> 1; if(judge(mid)){ i = mid * 2 + flag; ans = max(ans,i); low = mid + 1; }else high = mid - 1; } printf("%d\n",ans); } return 0; }