poj 1743 给定一个字符串,求最长重复子串,且这两个子串不重叠
二分答案,判断答案k是否可行时,把后缀数组分成若干组,每组中重复子串的长度都大于或等于k(即height大于等于k),如果本组中sa的最大最小值之差大于k就满足不重复,即这个k可行
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=20010;
int sa[maxn],t[maxn],t2[maxn],c[maxn],n,s[maxn];
int Rank[maxn],height[maxn];
void get_sa(int m)
{
int i,*x=t,*y=t2;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(i=n-k;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void get_height()
{
int i,j,k=0;
for(i=1;i<n;i++) Rank[sa[i]]=i;
for(i=0;i<n-1;i++)
{
if(k)k--;
j=sa[Rank[i]-1];
while(s[i+k]==s[j+k]) k++;
height[Rank[i]]=k;
}
}
bool judge(int k)
{
int maxn,minn;
maxn=-1;minn=40000;//这里把sa的范围给写成到200了..wa的不要不要的..要看清楚写的是哪个数组的范围..
for(int i=2;i<=n;i++)
{
maxn=max(sa[i-1],maxn);
minn=min(sa[i-1],minn);
if(i<n && height[i]<k)
{
if(maxn-minn>k)return true;
maxn=-1;minn=40000;
}
}
if(maxn-minn<=k)return false;
else return true;
}
int main()
{
int i;
while(scanf("%d",&n)!=EOF)
{
if(n==0)break;
for(i=0;i<n;i++) scanf("%d",&s[i]);
if(n<5){printf("0\n");continue;}
for(i=0;i<n-1;i++) s[i]=s[i+1]-s[i]+100;
s[n-1]=0;
get_sa(200);
get_height();
int l=4,r=n-1,mid;
while(r-l>1)
{
mid=(l+r)>>1;
if(judge(mid))l=mid;
else r=mid;
}
if(judge(r)) printf("%d\n",r+1);
else if(judge(l)) printf("%d\n",l+1);
else printf("0\n");
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000005;
int sa[maxn],t[maxn],t2[maxn],c[maxn+5],n,p,s[maxn];
int Rank[maxn],height[maxn];
void get_sa(int m)
{
int i,*x=t,*y=t2;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(i=n-k;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void get_height()
{
int i,j,k=0;
for(i=1;i<n;i++) Rank[sa[i]]=i;
for(i=0;i<n-1;i++)
{
if(k)k--;
j=sa[Rank[i]-1];
while(s[i+k]==s[j+k]) k++;
height[Rank[i]]=k;
}
}
bool judge(int m)
{
int cnt=0;
for(int i=2;i<=n;i++)
{
cnt++;
if(i<n && height[i]<m)
{
if(cnt>=p)return true;
cnt=0;
}
}
if(cnt<p)return false;
else return true;
}
int main()
{
int i;
scanf("%d%d",&n,&p);
for(i=0;i<n;i++) scanf("%d",&s[i]);
s[n++]=0;
get_sa(maxn);
get_height();
int l=1,r=n,mid;
while(r-l>1)
{
mid=(l+r)>>1;
if(judge(mid))l=mid;
else r=mid;
}
if(judge(r)) printf("%d\n",r);
else if(judge(l)) printf("%d\n",l);
return 0;
}