您的位置:首页 > 其它

bupt 204 Palindrome 求字符串任意区间的最长回文子串 二分答案+后缀数组

2011-07-28 14:57 417 查看
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.

// My Code

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

///后缀数组 倍增算法

const int maxn=400010;

int wa[maxn],wb[maxn],wv[maxn],wn[maxn],a[maxn],sa[maxn];

int cmp(int* r,int a,int b,int l)

{return r[a]==r[b]&&r[a+l]==r[b+l];}

/**n为字符串长度,m为字符的取值范围,r为字符串。后面的j为每次排

序时子串的长度*/

void DA(int* r,int* sa,int n,int m)

{

int i,j,p,*x=wa,*y=wb,*t;

///对R中长度为1的子串进行基数排序

for(i=0;i<m;i++)wn[i]=0;

for(i=0;i<n;i++)wn[x[i]=r[i]]++;

for(i=1;i<m;i++)wn[i]+=wn[i-1];

for(i=n-1;i>=0;i--)sa[--wn[x[i]]]=i;

for(j=1,p=1;p<n;j*=2,m=p)

{

/**利用了上一次基数排序的结果,对待排序的子串的第二关键字进行

了一次高效地基数排序*/

for(p=0,i=n-j;i<n;i++)y[p++]=i;

for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;

///基数排序

for(i=0;i<n;i++)wv[i]=x[y[i]];

for(i=0;i<m;i++)wn[i]=0;

for(i=0;i<n;i++)wn[wv[i]]++;

for(i=1;i<m;i++)wn[i]+=wn[i-1];

for(i=n-1;i>=0;i--)sa[--wn[wv[i]]]=y[i];

///当p=n的时候,说明所有串都已经排好序了

///在第一次排序以后,_rank数组中的最大值小于p,所以让m=p

for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)

x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;

}

return;

}

///后缀数组 计算height数组

/**

height数组的值应该是从height[1]开始的,而且height[1]应该是等于0的。

原因是,+因为我们在字符串后面添加了一个0号字符,所以它必然是最小的

一个后缀。而字符串中的其他字符都应该是大于0的(前面有提到,使用倍

增算法前需要确保这点),所以排名第二的字符串和0号字符的公共前缀

(即height[1])应当为0.在调用calheight函数时,要注意height数组的范

围应该是[1..n]。所以调用时应该是calheight(r,sa,n)

而不是calheight(r,sa,n+1)。*/

int _rank[maxn],height[maxn];

void calheight(int* r,int* sa,int n)

{

int i,j,k=0;

for(i=1;i<=n;i++)_rank[sa[i]]=i;

for(i=0;i<n;height[_rank[i++]]=k)

for(k?k--:0,j=sa[_rank[i]-1];r[i+k]==r[j+k];k++);

return;

}

//RMQ 求任意区间的最小值

int d[maxn];

int dpmin[maxn][20];

void creat_dpmin(int n)

{

int i,j;

for(i=1;i<=n;i++) dpmin[i][0]=d[i];

for(j=1;j<=log(double(n+1))/log(2.0);j++)

{

for(i=1;i+(1<<j)-1<=n;i++)

{

dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);

}

}

}

//求任意区间的最小值

int get_min(int x,int y)

{

int k=(int)(log(double(y-x+1))/log(2.0));

return min(dpmin[x][k],dpmin[y-(1<<k)+1][k]);

}

//后缀数组 + RMQ

//求第i个后缀和第j个后缀的最长公共前缀

int get_min_lcp(int x,int y)

{

x=_rank[x],y=_rank[y];

if(x>y) swap(x,y);

x++;//利用height数组

int k=(int)(log(double(y-x+1))/log(2.0));

return min(dpmin[x][k],dpmin[y-(1<<k)+1][k]);

}

int n1,n2;

char str1[maxn/2],str2[maxn/2];

int l[maxn/2],r[maxn/2];

int ans[maxn/2];

int dpmax[maxn/2][18];

void create_Dpmax1(int n){

int i , j;

for( i = 1 ; i <= n ; i++ )

dpmax[i][0] = d[i];

for( j = 1 ; j <= log((double)(n+1))/log(2.0) ; j++ ){

for( i = 1 ; i+(1<<j)-1 <= n ; i++ ){

dpmax[i][j] = max( dpmax[i][j-1] , dpmax[i+(1<<(j-1))][j-1] );

}

}

}

int getmax1( int a , int b ){

int k = (int)(log((double)(b-a+1))/log(2.0));

return max( dpmax[a][k] , dpmax[b-(1<<k)+1][k] );

}

void create_Dpmax2(int n){

int i , j;

for( i = 1 ; i <= n ; i++ )

dpmax[i][0] = d[i+n1];

for( j = 1 ; j <= log((double)(n+1))/log(2.0) ; j++ ){

for( i = 1 ; i+(1<<j)-1 <= n ; i++ ){

dpmax[i][j] = max( dpmax[i][j-1] , dpmax[i+(1<<(j-1))][j-1] );

}

}

}

int getmax2( int a , int b ){

int k = (int)(log((double)(b-a+1))/log(2.0));

return max( dpmax[a][k] , dpmax[b-(1<<k)+1][k] );

}

void read()

{

scanf("%s",str1);memcpy(str2,str1,sizeof(str1));

n1=strlen(str1),n2=strlen(str2);

reverse(str2,str2+n2);

for(int i=0;i<n1;i++) a[i]=(int)str1[i];

a[n1]=280;

for(int i=0;i<n2;i++) a[n1+i+1]=(int) str2[i];

int n=n1+n2+1;

a
=0;

DA(a,sa,n+1,300);

calheight(a,sa,n);

//.........

for(int i=1;i<=n;i++) d[i]=height[i];

creat_dpmin(n);

//int ans=0,pos;

for(int i=0;i<n1;i++)//枚举回文串中心

{

int t=get_min_lcp(i,n1+n1-i)*2-1;//回文串是奇数情况 t回文串长度

d[i+1]=t/2+1;//odd half

//if(t>ans) ans=t,pos=i;

if(i>0)//回文串是偶数数情况 t回文串长度

{

t=get_min_lcp(i,n1+n1-i+1)*2;

d[i+n1]=t/2;//even half

//if(t>ans) ans=t,pos=i;

}

}

create_Dpmax1(n1);

int q;scanf("%d",&q);int tq=q;

int pl=0;

while(q--)

{

scanf("%d%d",&l[pl],&r[pl]);

if(l[pl]>r[pl]) swap(l[pl],r[pl]);

int it=r[pl]-l[pl]+1;

int low,high;

//odd

low=0;high=it+1;

while(low<high)

{

int mid=(low+high)/2;

//cout<<"low="<<low<<"..."<<"high="<<high<<"..."<<"mid="<<mid<<endl;

int flag;

int tl=l[pl]+mid-1,tr=r[pl]-mid+1;

if(tl>tr) flag=0;

else

{

int cnt=getmax1(tl,tr);

//cout<<"tl="<<tl<<".."<<"tr="<<tr<<".."<<"cnt="<<cnt<<endl<<endl;

if(cnt>=mid) flag=1;

else flag=0;

}

if(flag) low=mid+1;

else high=mid;

}

//cout<<"odd"<<"..."<<"low="<<low<<endl;

ans[pl++]=(low-1)*2-1;

}

create_Dpmax2(n1-1);

pl=0;

while(tq--)

{

int it=r[pl]-l[pl]+1;

int low,high;

//even

low=0,high=it+1;

while(low<high)

{

int mid=(low+high)/2;

int tl=l[pl]+mid-1,tr=r[pl]-mid;

int flag;

if(tl>tr) flag=0;

else

{

int cnt=getmax2(tl,tr);

if(cnt>=mid) flag=1;

else flag=0;

}

if(flag) low=mid+1;

else high=mid;

}

ans[pl]=max(ans[pl],2*(low-1));

printf("%d\n",ans[pl++]);

}

}

int main()

{

int ci;scanf("%d",&ci);

while(ci--)

{

read();

}

return 0;

}

//标程

#include<vector>

#include<list>

#include<map>

#include<set>

#include<deque>

#include<queue>

#include<stack>

#include<bitset>

#include<algorithm>

#include<functional>

#include<numeric>

#include<utility>

#include<iostream>

#include<sstream>

#include<iomanip>

#include<cstdio>

#include<cmath>

#include<cstdlib>

#include<cctype>

#include<string>

#include<cstring>

#include<cstdio>

#include<cmath>

#include<cstdlib>

#include<ctime>

#include<climits>

#include<complex>

#define sz(x) ((int)((x).size())))

#define rep(i,n) for (int i=0;i<n;i++)

#define mp make_pair

#define pb push_back

#define all(x) x.begin(),x.end()

#define clr(x) memset((x),0,sizeof(x))

using namespace std;

typedef vector<int> vi;

typedef vector<string> vs;

typedef pair<int,int> pii;

typedef vector<pii> vpi;

char s[500000],t[500000];

int len[500000];

void palindrome(char*cs)

{

int n =strlen(cs);

for (int i = 0, j = 0, k; i < n * 2; i += k, j = max(j - k, 0))

{

while (i - j >= 0 && i + j + 1 < n * 2

&& cs[(i - j) / 2] == cs[(i + j + 1) / 2]) j++;

len[i] = j;

for (k = 1; i - k >= 0 && j - k >= 0 && len[i - k] != j - k; k++)

{

len[i + k] = min(len[i - k], j - k);

}

}

}

const int maxn=250010;

int val[maxn],val1[maxn];

int Max[20][maxn],Max1[20][maxn];

int idx[maxn];

int n;

void init()

{

idx[0]=-1;

int i,j,k;

for (i=1;i<=n;i++)

{

idx[i]=(i&(i-1))?idx[i-1]:idx[i-1]+1;

Max[0][i]=val[i];

Max1[0][i]=val1[i];

}

for (i=1;i<=idx
;i++)

{

int lim=n+1-(1<<i);

for (j=1;j<=lim;j++)

{

Max[i][j]=max(Max[i-1][j],Max[i-1][j+(1<<i>>1)]);

Max1[i][j]=max(Max1[i-1][j],Max1[i-1][j+(1<<i>>1)]);

}

}

}

int getval(int x,int y)

{

int t=idx[y-x+1];

y-=(1<<t)-1;

return max(Max[t][x],Max[t][y]);

}

int gaoval(int x,int y)

{

int t=idx[y-x+1];

y-=(1<<t)-1;

return max(Max1[t][x],Max1[t][y]);

}

int main()

{

freopen("C:\\Users\\daizhy\\Documents\\output.txt","r",stdin);

freopen("C:\\Users\\daizhy\\Documents\\output1.txt","w",stdout);

int i,j,k,cas;

scanf("%d",&cas);

while (cas--)

{

scanf("%s",s);

int l=strlen(s);

palindrome(s);

for (i=0;i<2*l-1;i+=2)

{

val[i/2+1]=len[i];

}

for (i=1;i<2*l-1;i+=2)

{

val1[(i+1)/2]=len[i];

//printf("%d %d\n",(i+1)/2,len[i]);

}

n=l;

init();

int q;

scanf("%d",&q);

while (q--)

{

int x,y;

scanf("%d%d",&x,&y);

int low=0,high,mid;

int ans=1;

int lt=(y-x+1);

if (lt%2==1)high=lt/2;

else high=(lt-1)/2;

while (low<=high)

{

mid=(low+high)>>1;

int ll=2*mid+1;

int tmp=getval(x+mid,y-mid);

if (tmp>=ll)

{

low=mid+1;

ans=max(ans,ll);

}

else

{

high=mid-1;

}

}

low=0;

if (lt%2==0)high=lt/2;

else high=(lt-1)/2;

while (low<=high)

{

mid=(low+high)>>1;

int ll=2*mid;

int tmp=gaoval(x+mid-1,y-mid);

if (tmp>=ll)

{

low=mid+1;

ans=max(ans,ll);

}

else

{

high=mid-1;

}

}

printf("%d\n",ans);

}

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: