zoukankan      html  css  js  c++  java
  • 【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
    ",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
  • 相关阅读:
    可图性判定HavelHakimi定理
    并查集入门
    js数组和函数应用
    DOM用法及应用
    javascript基础知识
    表单
    PHP变量
    30天自制操作系统开发笔记——IDT中断描述符表
    《30天自制操作系统》学习笔记——汇编程序磁盘BIOS调用
    汇编指令: LGDT、LIDT、LLDT、LMSW、LOADALL、LOADALL286、LOCK、LODSB、LODSW、LODSD
  • 原文地址:https://www.cnblogs.com/g-word/p/3459033.html
Copyright © 2011-2022 走看看