/*
suffix数组:第i位到最后的字符串
sa数组:将排序后的后缀的开头位置顺次放入SA中,称为后缀数组
rank数组:令rank[i]保存suffix[i]在排序中的名次,名次数组
*/
#include "stdio.h"
#include "string.h"
#define maxn 20004
#define maxm 1000005
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[maxn],wb[maxn],wv[maxn],ws[maxm];
int c0(int *r,int a,int b)
{return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}
int c12(int k,int *r,int a,int b)
{if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];}
void sort(int *r,int *a,int *b,int n,int m)
{
int i;
for(i=0;i<n;i++) wv[i]=r[a[i]];
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) b[--ws[wv[i]]]=a[i];
return;
}
void dc3(int *r,int *sa,int n,int m)
{
int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
r[n]=r[n+1]=0;
for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
sort(r+2,wa,wb,tbc,m);
sort(r+1,wb,wa,tbc,m);
sort(r,wa,wb,tbc,m);
for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
if(p<tbc) dc3(rn,san,tbc,p);
else for(i=0;i<tbc;i++) san[rn[i]]=i;
for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
if(n%3==1) wb[ta++]=n-1;
sort(r,wb,wa,ta,m);
for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
for(i=0,j=0,p=0;i<ta && j<tbc;p++)
sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
for(;i<ta;p++) sa[p]=wa[i++];
for(;j<tbc;p++) sa[p]=wb[j++];
return;
}
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;
}
int RMQ[maxn];
int mm[maxn];
int best[20][maxn];
void initRMQ(int n)
{
int i,j,a,b;
for(mm[0]=-1,i=1;i<=n;i++)
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
for(i=1;i<=n;i++) best[0][i]=i;
for(i=1;i<=mm[n];i++)
for(j=1;j<=n+1-(1<<i);j++)
{
a=best[i-1][j];
b=best[i-1][j+(1<<(i-1))];
if(RMQ[a]<RMQ[b]) best[i][j]=a;
else best[i][j]=b;
}
return;
}
int askRMQ(int a,int b)
{
int t;
t=mm[b-a+1];b-=(1<<t)-1;
a=best[t][a];b=best[t][b];
return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b)//从头开始比较a和b的对应字符持续相等的最远值
{
int t;
a=rank[a];b=rank[b];
if(a>b) {t=a;a=b;b=t;}
return(height[askRMQ(a+1,b)]);
}
/*
*/
char st[maxn];
int r[maxn*3],sa[maxn*3];
/*求最长回文长
int main()
{
int i,n,len,k,ans=0,w;
scanf("%s",st);
len=strlen(st);
for(i=0;i<len;i++) r[i]=st[i];
r[len]=1;
for(i=0;i<len;i++) r[i+len+1]=st[len-1-i];
n=len+len+1;
r[n]=0;
dc3(r,sa,n+1,128);
calheight(r,sa,n);
for(i=1;i<=n;i++) RMQ[i]=height[i];
initRMQ(n);
for(i=0;i<len;i++)
{
k=lcp(i,n-i);
if(k*2>ans) ans=k*2,w=i-k;
k=lcp(i,n-i-1);
if(k*2-1>ans) ans=k*2-1,w=i-k+1;
}
st[w+ans]=0;
printf("%s\n",st+w);
return 0;
}*/
/*求最大公共字串长
int main()
{
int i,j,n,ans=0;
scanf("%s",st);
j=strlen(st);
st[j]=1;
scanf("%s",st+j+1);
n=strlen(st);
for(i=0;i<n;i++) r[i]=st[i];
r[n]=0;
dc3(r,sa,n+1,128);
calheight(r,sa,n);
for(i=2;i<=n;i++)
if(height[i]>ans)
if((j<sa[i-1] && j>sa[i])
|| (j>sa[i-1] && j<sa[i])) ans=height[i];
printf("%d\n",ans);
return 0;
}
*/
/*不可重叠最长重复子串
POJ 1743 最长重复子串(不可重叠)
题意:
有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
1.长度至少为5个音符
2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。)
3.重复出现的同一主题不能有公共部分。
int check(int *sa,int n,int k)
{
int i,max=sa[1],min=sa[1];
for(i=2;i<=n;i++)
{
if(height[i]<k) max=min=sa[i];
else
{
if(sa[i]<min) min=sa[i];
if(sa[i]>max) max=sa[i];
if(max-min>k) return(1);
}
}
return(0);
}
int main()
{
int i,j=0,k,n;
int min,mid,max;
scanf("%d",&n);
while(n!=0)
{
n--;
for(i=0;i<n;i++)
scanf("%d",&r[i]);
for(i=0;i<n;i++)
r[i]=r[i]-r[i+1]+90;
r[n]=0;
dc3(r,sa,n+1,200);
calheight(r,sa,n);
min=1;max=n/2;
while(min<=max)
{
mid=(min+max)/2;
if(check(sa,n,mid)) min=mid+1;
else max=mid-1;
}
if(max>=4) printf("%d\n",max+1);
else printf("0\n");
scanf("%d",&n);
}
return 0;
}
*/
/*
可重叠的 k 次最长重复子串
给定一个长度为n的整数序列,求其中至少出现k次的子序列长度最长为多长
int check(int n,int k,int mid)
{
int i,s=1;
for(i=1;i<=n;i++)
if(height[i]>=mid)
{
s++;
if(s>=k) return(1);
}
else s=1;
return(0);
}
int main()
{
int i,k,n;
int min,mid,max;
scanf("%d %d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%d",&r[i]);
r[i]++;
}
r[n]=0;
dc3(r,sa,n+1,1000002);
calheight(r,sa,n);
min=1;max=n;
while(min<=max)
{
mid=(min+max)/2;
if(check(n,k,mid)) min=mid+1;
else max=mid-1;
}
printf("%d\n",max);
return 0;
}
*/
/*
不相同的连续子串的个数
int main()
{
int i,n,t,ans;
scanf("%d",&t);
while(t-->0)
{
scanf("%s",st);
n=strlen(st);
for(i=0;i<n;i++) r[i]=st[i];
r[n]=0;
dc3(r,sa,n+1,128);
calheight(r,sa,n);
ans=n*(n+1)/2;
for(i=1;i<=n;i++) ans-=height[i];
printf("%d\n",ans);
}
return 0;
}
*/
/*
长度不小于 k 的公共子串的个数
int f[maxn];
int a[maxn],b[maxn],c;
long long ss,ans;
int main()
{
int i,k,l,n,t;
scanf("%d",&k);
while(k!=0)
{
scanf("%s",st);
l=strlen(st);
st[l]=1;
scanf("%s",st+l+1);
n=strlen(st);
for(i=0;i<n;i++) r[i]=st[i];
r[n]=0;
dc3(r,sa,n+1,128);
calheight(r,sa,n);
for(i=2;i<=n;i++)
{
f[i]=sa[i]<l;
height[i]-=k-1;
if(height[i]<0) height[i]=0;
}
height[n+1]=0;
a[0]=-1;ans=0;
for(t=0;t<=1;t++)
for(c=0,ss=0,i=2;i<=n;i++)
{
if(f[i]!=t) ans+=ss;
c++;
a[c]=height[i+1];
b[c]=f[i]==t;
ss+=(long long)a[c]*b[c];
while(a[c-1]>=a[c])
{
ss-=(long long)(a[c-1]-a[c])*b[c-1];
a[c-1]=a[c];
b[c-1]+=b[c];
c--;
}
}
printf("%I64d\n",ans);
scanf("%d",&k);
}
return 0;
}
*/
后缀数组_DC3(模板大全)
最新推荐文章于 2023-07-24 16:24:22 发布