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