【po3693】Maximum repetition substring

题意:

给定一个字符串 求重复次数最多的连续重复子串 并输出字典序最小方案

 

题解:

枚举子串长度L 显然如果重复次数>1 那么答案串肯定包含s[1],s[1+L],s[1+L*2],...中的两个

枚举被答案包含位置 1+L*i

将1+L*i和1+L*(i+1) 向前、向后匹配 记匹配距离和为k 则重复次数为k/L

这样我们就能知道最多重复次数ans是多少

但是这题还要求字典序最小方案

求方案需要再进行一次枚举 方法同上

当重复次数和答案相等时 更新方案

但是我们知道 包含1+L*i 重复次数为k/L 的方案可能有L种 这样总时间就可能达到O(n^2)

因为这L种方案的下标是连续的 并且他们的长度相等

我们可以用线段树维护下标为x到y的rank最小值位置在哪 即可log(n)完成一个询问

总复杂度O(nlog^2(n))

(但是好像常数写好一点不用线段树也能过- - 我就没加跑得比AK加了还快。。)

 

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 const int N=200005;
  4 int n,ans,ansx,ansy,x[N],y[N],sa[N],rank[N],hi[N],ws[N],a[N],lon,min[N][20];
  5 char s[N];
  6 void sort(int t){
  7     for (int i=1;i<=n;i++) ++ws[x[y[i]]];
  8     for (int i=1;i<=t;i++) ws[i]+=ws[i-1];
  9     for (int i=n;i;i--) sa[ws[x[y[i]]]--]=y[i];
 10     for (int i=1;i<=t;i++) ws[i]=0;
 11 }
 12 bool check(int a,int b,int c){ return y[a]==y[b] && y[a+c]==y[b+c]; }
 13 void makesa(){
 14     int p=0,tt=200;
 15     for (int i=1;i<=n;i++) x[i]=a[i],y[i]=i;
 16     sort(tt);
 17     for (int j=1;j<=n;j<<=1,tt=p,p=0){
 18         for (int i=n-j+1;i<=n;i++) y[++p]=i;
 19         for (int i=1;i<=n;i++)
 20         if (sa[i]>j) y[++p]=sa[i]-j;
 21         sort(tt);
 22         for (int i=1;i<=n;i++) y[i]=x[i];
 23         x[sa[1]]=p=1;
 24         for (int i=2;i<=n;i++)
 25         x[sa[i]]=check(sa[i],sa[i-1],j) ? p : ++p;
 26     }
 27 }
 28 void makehi(){
 29     for (int i=1;i<=n;i++) rank[sa[i]]=i;
 30     for (int i=1,k=0;i<=n;hi[rank[i++]]=k)
 31     if (rank[i]==1) k=0;
 32     else for (k=k ? k-1 : k;a[i+k]==a[sa[rank[i]-1]+k];++k);
 33 }
 34 int minn(int x,int y){ return x<y ? x : y; }
 35 void swap(int &x,int &y){ int t=x; x=y,y=t; }
 36 void makemin(){
 37     for (int i=n;i;i--){
 38         min[i][0]=hi[i];
 39         for (int j=1;i+(1<<j)<=n;j++)
 40         min[i][j]=minn(min[i][j-1],min[i+(1<<(j-1))][j-1]);
 41     }
 42 }
 43 int find(int t){
 44     int l=0,r=20,mid;
 45     while (l+1<r){
 46         mid=(l+r)/2;
 47         if ((1<<mid)>t) r=mid;
 48         else l=mid;
 49     }
 50     return l;
 51 }
 52 int getlon(int x,int y){
 53     x=rank[x],y=rank[y];
 54     if (x>y) swap(x,y);
 55     int add=find(y-x);
 56     //while ((1<<add)<=y-x) ++add;
 57     //--add;
 58     return minn(min[x+1][add],min[y-(1<<add)+1][add]);
 59 }
 60 bool checkres(int resx,int resy){
 61     if (!ansx) return 1;
 62     int l1=resy-resx+1,l2=ansy-ansx+1,lon=getlon(resx,ansx);
 63     if (lon>=l1 || lon>=l2) return l1<l2;
 64     return rank[resx]<rank[ansx];
 65 }
 66 void makexy(int x,int y,int z){
 67     for (int i=x;i+z-1<=y;i++){
 68         int resx=i,resy=i+z-1;
 69         if (checkres(resx,resy)) ansx=resx,ansy=resy;
 70     }
 71 }
 72 void makeans(int bo){
 73     for (int i=1;i<lon;i++)
 74     for (int j=1+i;j<=lon;j+=i)
 75     if (a[j]==a[j-i]){
 76         int resx=j-i-getlon(n-(j-i)+1,n-j+1)+1,resy=j+getlon(j-i,j)-1,lon=resy-resx+1,res=lon/i;
 77         if (bo){
 78             if (res==ans) makexy(resx,resy,i*res);
 79         }else if (ans<res) ans=res;
 80     }
 81 }
 82 int main(){
 83     freopen("poj3693.in","r",stdin);
 84     freopen("poj3693.out","w",stdout);
 85     for (int t=1;scanf("%s",s),s[0]!='#';t++){
 86         printf("Case %d: ",t);
 87         lon=strlen(s);
 88         n=0;
 89         for (int i=0;i<lon;i++) a[++n]=s[i];
 90         a[++n]='~';
 91         for (int i=lon-1;i>=0;i--) a[++n]=s[i];
 92         a[n+1]=0;
 93         ans=1;
 94         ansx=ansy=0;
 95         makesa();
 96         makehi();
 97         makemin();
 98         makeans(0);
 99         if (ans==1) printf("%c\n",s[sa[1]-1]);
100         else{
101             if (t==6)
102             t=6;
103             makeans(1);
104             for (int i=ansx;i<=ansy;i++) printf("%c",s[i-1]);
105             puts("");
106         }
107     }
108     fclose(stdin);
109     fclose(stdout);
110 }
View Code

 

posted @ 2013-12-05 10:48  g_word  阅读(158)  评论(0编辑  收藏  举报