bupt 204 Palindrome

 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
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
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;
}

		


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值