http://acm.bupt.edu.cn/onlinejudge/newoj/showProblem/show_problem.php?problem_id=204
Palindrome
Accept:88 | Submit:270 |
Time Limit:5000MS | Memory Limit:65536KB |
Description
Given a string S,you are asked to find the longest palindrome in the substring [l,r].
Input
The first line is a number T which indicates the number of test cases
The first line is a number T which indicates the number of test cases
then follows a string s(length(s)<200000)
s can consists all ascii characters
Then an integer q,q querys(q<200000)
each query is two integer l,r.
find the longest palindrome in the substring [l,r].
Output
the answer for each query.
Sample Input
1
1
aaabbcc
5
1 7
1 4
2 3
4 5
2 5
Sample output
3
3
2
2
2
Hint
1 7 means aaabbcc the longest palindrome substring is aaa,whose length is 3.
4 5 means bb the longest palindrome substring is bb,whose length is 2.
题意:一个字符串,q个查询,查询的是给定区间内的子串的最长回文串。(s,q<200000)
分析:先求出以每个字符为中心的最长回文串长度(长度为奇偶情况),可以用后缀数组,但是Manacher算法求回文串实现简单且复杂度为O(n)。求出以每个字符为中心的回文串最长度后,假设保存在 p [ ] 中。对于每个查询,建设区间为[ l , r ],二分答案len ,那么只需在 p [ l + len/2,....... ,r - len /2 ] 中的最大值,用rmq预处理。时间复杂度O(nlogn).
#include<stdio.h>
#include<string.h>
#include<math.h>
#define min(a,b) (((a)<(b))?(a):(b))
#define Max(a,b) (((a)>(b))?(a):(b))
#define N 400050
char s[N],str[N];
int p[N];
int l,r,f[N][19];
void process(int n)//预处理
{
int i, j;
for (i = 0; i < n; i++)
f[i][0] = p[i]-1;
for (j = 1; (1 << j) <= n; j++)
for (i = 0; i + (1 << j) - 1 < n; i++)
if (f[i][j - 1] > f[i + (1 << (j - 1))][j - 1])
f[i][j] = f[i][j - 1];
else
f[i][j] = f[i + (1 << (j - 1))][j - 1];
}
int query(int s,int v)
{
int k=(int)(log((v-s+1)*1.0)/log(2.0));
return Max(f[s][k],f[v-(1<<k)+1][k]);
}
void calp(int n)
{
int i,mx=0,id;
p[0]=1;
for(i=1;i<=n;i++)
{
if(mx>i)
p[i]=min(p[2*id-i],mx-i);
else
p[i]=1;
for(;str[i+p[i]]==str[i-p[i]];p[i]++)
;
if(p[i]+i>mx)
{
mx=p[i]+i;
id=i;
}
}
}
int check(int s,int t,int key)
{
int temp=query(s,t);
if(key<=temp)
return 1;
return 0;
}
int bin(int left,int right)
{
int mid,ans,s,t;
while(left<=right)
{
mid=(left+right)>>1;
s=l*2+mid-1,t=r*2-mid+1;
if(check(s,t,mid))
{
ans=mid;
left=mid+1;
}
else
right=mid-1;
}
return ans;
}
int main()
{
int t,n,i,k,q;
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
n=strlen(s);
str[0]=1;
for(i=0,k=1;i<n;i++)
{
str[k++]=2;
str[k++]=s[i];
}
str[k++]=2;str[k]=0;
memset(p,0,sizeof(p));
calp(k-1);
process(k);
scanf("%d",&q);
for(i=0;i<q;i++)
{
scanf("%d%d",&l,&r);
int ans=bin(1,r-l+1);
printf("%d\n",ans);
}
}
return 0;
}