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