后缀数组论文题目

1.模板

2.ural1517最长公共子串

3.ural1297最长回文子串

4.spoj705不相同的子串的个数

5.spoj694不相同的子串的个数

6.spoj687重复次数最多的连续重复子串

7.spoj220每个字符串至少出现两次且不重叠的最长子串

8.pku3415长度不小于的公共子串的个数

9.pku3294不小于个字符串中的最长子串

10.pku3261可重叠的次最长重复子串

11.pku2774最长公共子串

12.pku1743不可重叠最长重复子串

13.pku1226

1.模板
#define maxn 1000001
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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)
{
    int t;
    a=rank[a];b=rank[b];
    if(a>b) {t=a;a=b;b=t;}
    return(height[askRMQ(a+1,b)]);
}
2.ural1517最长公共子串
给定两个字符串A 和B,求最长公共子串。
#include "stdio.h"
#define maxn 200002

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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;
}

char s[maxn];
int r[maxn],sa[maxn];
int main()
{
    int i,j,n,ans=0,w;
    scanf("%d",&j);
    scanf("%s",s);
    s[j]=1;
    scanf("%s",s+j+1);
    n=j+j+1;
    for(i=0;i<n;i++) r[i]=s[i];
    r[n]=0;
    da(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],w=sa[i];
    s[w+ans]=0;
    printf("%s\n",s+w);
    return 0;
}
3.ural1297最长回文子串
给定一个字符串,求最长回文子串。
#include "stdio.h"
#include "string.h"
#define maxn 2002

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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)
{
    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],sa[maxn];
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;
    da(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;
}
4.spoj705不相同的子串的个数
给定一个字符串,求不相同的子串的个数。
#include "stdio.h"
#include "string.h"
#define maxn 50001

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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;
}

char s[maxn];
int r[maxn],sa[maxn];
int main()
{
    int i,n,t;
    long long ans;
    scanf("%d",&t);
    while(t-->0)
    {
      scanf("%s",s);
      n=strlen(s);
      for(i=0;i<n;i++) r[i]=s[i];
      r[n]=0;
      da(r,sa,n+1,128);
      calheight(r,sa,n);
      ans=(long long)n*(n+1)/2;
      for(i=1;i<=n;i++) ans-=height[i];
      printf("%lld\n",ans);
    }
    return 0;
}
5.spoj694不相同的子串的个数
给定一个字符串,求不相同的子串的个数。
#include "stdio.h"
#include "string.h"
#define maxn 1001

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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;
}

char s[maxn];
int r[maxn],sa[maxn];
int main()
{
    int i,n,t,ans;
    scanf("%d",&t);
    while(t-->0)
    {
      scanf("%s",s);
      n=strlen(s);
      for(i=0;i<n;i++) r[i]=s[i];
      r[n]=0;
      da(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;
}
6.spoj687重复次数最多的连续重复子串
给定一个字符串,求重复次数最多的连续重复子串。
#include "stdio.h"
#define maxn 50001

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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)
{
    int t;
    a=rank[a];b=rank[b];
    if(a>b) {t=a;a=b;b=t;}
    return(height[askRMQ(a+1,b)]);
}

char c;
int r[maxn],sa[maxn];
int main()
{
    int i,j,jj,k,n,now,ans,nn;
    scanf("%d\n",&nn);
    while(nn-->0)
    {
      scanf("%d\n",&n);
      for(i=0;i<n;i++)
      {
        scanf("%c\n",&c);
        r[i]=c;
      }
      r[n]=0;
      da(r,sa,n+1,128);
      calheight(r,sa,n);
      for(i=1;i<=n;i++) RMQ[i]=height[i];
      initRMQ(n);
      ans=0;
      for(i=1;i<n;i++)
      {
        for(j=0;j+i<n;j+=i)
        {
          k=lcp(j,j+i);
          now=k/i;
          jj=j-(i-k%i);
          if(jj>=0)
          if(lcp(jj,jj+i)>=(i-k%i)) now++;
          if(now>ans) ans=now;
        }
      }
      printf("%d\n",ans+1);
    }
    return 0;
}
7.spoj220每个字符串至少出现两次且不重叠的最长子串
给定n 个字符串,求在每个字符串中至少出现两次且不重叠的最长子串。
#include "stdio.h"
#include "string.h"
#define maxn 100011

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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 r[maxn],sa[maxn];
int who[maxn],min[11],max[11];
int len,n;
int check(int mid)
{
    int i,j,k;
    for(i=2;i<=len;i=j+1)
    {
      for(;height[i]<mid && i<=len;i++);
      for(j=i;height[j]>=mid;j++);
      if(j-i+1<n) continue;
      for(k=1;k<=n;k++) {min[k]=1000000;max[k]=-1;}
      for(k=i-1;k<j;k++)
      {
        if(sa[k]<min[who[sa[k]]]) min[who[sa[k]]]=sa[k];
        if(sa[k]>max[who[sa[k]]]) max[who[sa[k]]]=sa[k];
      }
      for(k=1;k<=n;k++) if(max[k]-min[k]<mid) break;
      if(k>n) return 1;
    }
    return 0;
}
char st[110];
int main()
{
    int i,j,k,min,mid,max,nn;
    scanf("%d",&nn);
    while(nn-->0)
    {
      scanf("%d",&n);
      len=0;
      for(i=1;i<=n;i++)
      {
        scanf("%s",st);
        k=strlen(st);
        for(j=0;j<k;j++)
        {
          r[j+len]=st[j]+10;
          who[j+len]=i;
        }
        r[len+k]=i;
        who[len+k]=0;
        len+=k+1;
      }
      len--;
      r[len]=0;
      da(r,sa,len+1,138);
      calheight(r,sa,len);
      height[len+1]=-1;
      min=1;max=5000;
      while(min<=max)
      {
        mid=(min+max)>>1;
        if(check(mid)) min=mid+1;
        else max=mid-1;
      }
      printf("%d\n",max);
    }
    return 0;
}

8.pku3415长度不小于k 的公共子串的个数
给定两个字符串A 和B,求长度不小于k 的公共子串的个数(可以相同)。
样例1:
A=“xx”,B=“xx”,k=1,长度不小于k 的公共子串的个数是5。
样例2:
A =“aababaa”,B =“abaabaa”,k=2,长度不小于k 的公共子串的个数是22。
#include "stdio.h"
#include "string.h"
#define maxn 200002

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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 r[maxn],sa[maxn];
char s[maxn];
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",s);
      l=strlen(s);
      s[l]=1;
      scanf("%s",s+l+1);
      n=strlen(s);
      for(i=0;i<n;i++) r[i]=s[i];
      r[n]=0;
      da(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;
}

9.pku3294不小于k 个字符串中的最长子串
给定n 个字符串,求出现在不小于k 个字符串中的最长子串。
算法分析:
将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,
求后缀数组。然后二分答案,用和例3 同样的方法将后缀分成若干组,判断每组
的后缀是否出现在不小于k 个的原串中。这个做法的时间复杂度为O(nlogn)。
#include "stdio.h"
#include "string.h"
#define maxn 100101

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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 r[maxn],sa[maxn];
int who[maxn],yes[101]={0},ii=0;
int len,n,nn;
int ans[maxn],ss;
int check(int mid)
{
    int i,j,k,t,s,flag=0;
    for(i=2;i<=len;i=j+1)
    {
      for(;height[i]<mid && i<=len;i++);
      for(j=i;height[j]>=mid;j++);
      if(j-i+1<nn) continue;
      ii++;s=0;
      for(k=i-1;k<j;k++)
      if((t=who[sa[k]])!=0)
      if(yes[t]!=ii) yes[t]=ii,s++;
      if(s>=nn) if(flag) ans[++ss]=sa[i-1];
      else ans[ss=1]=sa[i-1],flag=1;
    }
    return(flag);
}
char st[1010];
int main()
{
    int i,j,k,flag=0,min,mid,max;
    scanf("%d",&n);
    while(n!=0)
    {
      len=0;
      for(i=1;i<=n;i++)
      {
        scanf("%s",st);
        k=strlen(st);
        for(j=0;j<k;j++)
        {
          r[j+len]=st[j]+100;
          who[j+len]=i;
        }
        r[len+k]=i;
        who[len+k]=0;
        len+=k+1;
      }
      len--;
      r[len]=0;
      da(r,sa,len+1,227);
      calheight(r,sa,len);
      height[len+1]=-1;
      nn=n/2+1;
      min=1;max=1000;
      while(min<=max)
      {
        mid=(min+max)>>1;
        if(check(mid)) min=mid+1;
        else max=mid-1;
      }
      if(flag) printf("\n");
      else flag=1;
      if(max==0) printf("?\n");
      else for(i=1;i<=ss;i++)
      {
        k=ans[i];
        for(j=0;j<max;j++) printf("%c",r[k+j]-100);
        printf("\n");
      }
      scanf("%d",&n);
    }
    return 0;
}

10.pku3261可重叠的k 次最长重复子串
给定一个字符串,求至少出现k 次的最长重复子串,这k 个子串可以重叠。
算法分析:
这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组。不
同的是,这里要判断的是有没有一个组的后缀个数不小于k。如果有,那么存在
k 个相同的子串满足条件,否则不存在。这个做法的时间复杂度为O(nlogn)。
#include "stdio.h"
#define maxn 20001
#define maxm 1000002

int wa[maxn],wb[maxn],wv[maxn],ws[maxm];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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 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 r[maxn],sa[maxn];
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;
    da(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;
}

11.pku2774最长公共子串
给定两个字符串A 和B,求最长公共子串。
#include "stdio.h"
#include "string.h"
#define maxn 200002

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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;
}

char s[maxn];
int r[maxn],sa[maxn];
int main()
{
    int i,j,n,ans=0;
    scanf("%s",s);
    j=strlen(s);
    s[j]=1;
    scanf("%s",s+j+1);
    n=strlen(s);
    for(i=0;i<n;i++) r[i]=s[i];
    r[n]=0;
    da(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;
}

12.pku1743不可重叠最长重复子串
给定一个字符串,求最长重复子串,这两个子串不能重叠。
#include "stdio.h"
#define maxn 20000

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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 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 r[maxn],sa[maxn];
int main()
{
    int i,j=0,k,n;
    int min,mid,max;
    scanf("%d",&n);
    while(n!=0)
    {
      n--;
      scanf("%d",&j);
      for(i=0;i<n;i++)
      {
        scanf("%d",&k);
        r[i]=k-j+100;
        j=k;
      }
      r[n]=0;
      da(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;
}

13.pku1226
#include "stdio.h"
#include "string.h"
#define maxn 20201

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*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=1,p=1;p<n;j*=2,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<n;i++) wv[i]=x[y[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--) sa[--ws[wv[i]]]=y[i];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     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 r[maxn],sa[maxn];
int who[maxn],yes[101]={0},ii=0;
int len,n;
int check(int mid)
{
    int i,j,k,t,s;
    for(i=2;i<=len;i=j+1)
    {
      for(;height[i]<mid && i<=len;i++);
      for(j=i;height[j]>=mid;j++);
      if(j-i+1<n) continue;
      ii++;s=0;
      for(k=i-1;k<j;k++)
      if((t=who[sa[k]])!=0)
      if(yes[t]!=ii) yes[t]=ii,s++;
      if(s>=n) return 1;
    }
    return 0;
}
char st[110];
int main()
{
    int i,j,k,min,mid,max,nn;
    scanf("%d",&nn);
    while(nn-->0)
    {
      scanf("%d",&n);
      len=0;
      for(i=1;i<=n;i++)
      {
        scanf("%s",st);
        k=strlen(st);
        for(j=0;j<k;j++)
        {
          r[j+len]=st[j]+200;
          who[j+len]=i;
        }
        r[len+k]=2*i-1;
        who[len+k]=0;
        len+=k+1;
        for(j=0;j<k;j++)
        {
          r[j+len]=st[k-1-j]+200;
          who[j+len]=i;
        }
        r[len+k]=2*i;
        who[len+k]=0;
        len+=k+1;
      }
      len--;
      r[len]=0;
      da(r,sa,len+1,328);
      calheight(r,sa,len);
      height[len+1]=-1;
      min=1;max=100;
      while(min<=max)
      {
        mid=(min+max)>>1;
        if(check(mid)) min=mid+1;
        else max=mid-1;
      }
      if(n==1) max=len/2;
      printf("%d\n",max);
    }
    return 0;
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值