4
30
2016
0

后缀数组练习

CTSC&APIO感觉自己水平太低,完全没法做……

所以打算利用在北京的这段时间提高一下自己的OI水平

后缀数组虽然会写,但是仅限于会敲模版。。

所以我打算把罗穗骞论文里面的所有题写一遍

----------------------------------------

POJ 2774

两个串连一起搞完后缀数组然后求height最大值判断一下前后是否分别属于两个不同的串就好了

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=200005;

int n1,n2,n,rank[N],sa[N],rank2[N],wa[N],ws[N],height[N];
char s1[N],s2[N],s[2*N];

int cmp(int *r,int a,int b,int l){return (r[a]==r[b])&(r[a+l]==r[b+l]);}

void GetSA(char *r,int *sa,int n,int m){
int i,j,p,*x=rank,*y=rank2,*t;
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[x[i]=r[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
for(j=p=1;p<n;j<<=1,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<m;i++)ws[i]=0;
	for(i=0;i<n;i++)ws[wa[i]=x[y[i]]]++;
    for(i=1;i<m;i++)ws[i]+=ws[i-1];
    for(i=n-1;i>=0;i--)sa[--ws[wa[i]]]=y[i];
    for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}

void CalHeight(char *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++);
}
}

bool Diff(int x){return (sa[x]<n1 && sa[x-1]>=n1)||(sa[x]>=n1 && sa[x-1]<n1);}

int Solve(){
int MxHeight=0;
for(int i=2;i<=n;i++){
	if(height[i]>MxHeight && Diff(i))MxHeight=height[i];
}
return MxHeight;
}

int main(){
freopen("2774.in","r",stdin);
freopen("2774.out","w",stdout);
scanf("%s %s",s1,s2);
n1=strlen(s1);
n2=strlen(s2);
n=n1+n2;
for(int i=0;i<n1;i++)s[i]=s1[i];
for(int i=n1;i<n;i++)s[i]=s2[i-n1];
s[n]=0;
GetSA(s,sa,n+1,128);
CalHeight(s,sa,n);
printf("%d\n",Solve());
return 0;
}

----------------------------------------

POJ 1743

先差分,然后二分答案k,然后对于height分组(height[i]记录的是sa[i]和sa[i-1]的LCP),那么因为字典序相邻的后缀在sa里的顺序是连续的,那么我们对于判定答案k是否合法的方法就是找到连续的height,它们的值都不小于k(保证重复的串长大于等于k),然后如果组内最靠前和最靠后的位置差也大于等于k,那么这个方案就是合法的。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int N=200005,INF=2100000000;

int sa[N],rank[N],rank2[N],ws[N],s[N],wa[N],n,height[N];

int Abs(int x){return x>0?x:-x;}
int cmp(int *r,int a,int b,int l){return (r[a]==r[b])&(r[a+l]==r[b+l]);}

void GetSA(int *r,int *sa,int n,int m){
int i,j,p,*x=rank,*y=rank2,*t;
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[x[i]=r[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
for(j=p=1;p<n;j<<=1,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<m;i++)ws[i]=0;
    for(i=0;i<n;i++)ws[wa[i]=x[y[i]]]++;
    for(i=1;i<m;i++)ws[i]+=ws[i-1];
    for(i=n-1;i>=0;i--)sa[--ws[wa[i]]]=y[i];
    for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}

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

int Solve(int k){
int i=2,Mx,Mn;
while(1){
    while(i<=n && height[i]<k)i++;
    if(i>n)break;
    Mx=sa[i-1];Mn=sa[i-1];
    while(i<=n && height[i]>=k){Mn=min(Mn,sa[i]);Mx=max(Mx,sa[i]);i++;}
    if(Mx-Mn>=k)return 1;
}
return 0;
}

int Div(){
int l=4,r=n*2,ans=0;
while(l<=r){
    int mid=l+r>>1;
    if(Solve(mid)){l=mid+1;ans=mid;}
    else r=mid-1;
}
ans++;
return ans<5?0:ans;
}

int main(){
freopen("1743.in","r",stdin);
freopen("1743.out","w",stdout);
while(scanf("%d",&n),n){
    for(int i=0;i<n;i++)scanf("%d",&s[i]);
    if(n<10){puts("0");continue;}
    n--;
    for(int i=0;i<n;i++)s[i]=s[i+1]-s[i]+89;
    s[n]=0;
    for(int i=0;i<N;i++)wa[i]=ws[i]=0;
    GetSA(s,sa,n+1,200);
    Calheight(s,sa,n);
    printf("%d\n",Div());
}
return 0;
}

----------------------------------------

Category: OI | Tags: OI | Read Count: 669

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com