//Accepted    12004 KB    407 ms
 /*
     source:poj3693
     time  :20150819
     by    :songt
   */
 /*题解:
 搞了一天,总算弄完了
 首先,我们来明确一个问题 1.如果一个字符串S由一个子串S1长度为L重复K次得到,那么lcp(0,l)=(K-1)*L;
                               而如果一个字符串中存在lcp(i,i+L)=m,那么字符串中就存在重复m/L+1次的子串
                               这个可以画个图看下
 下面我们按照论文里的思路,枚举每个循环节的长度L,假设某个长度为L的子串在原字符中出现了两次以上,那么由
 容斥原理可知,这段连续重复的子串S一定包括了s[0],s[L],s[2*L],s[3*L],...中的连续的两个,这样我们可以枚举找到
 包括最开始的两个是哪两个,假设是s[i*L]和s[(i+1)*L],那么求lcp(i*L,(i+1)*L)=m,由1可知,原字符串中从i*L到(i+1)*L这段
 长度为L的子串,一定重复了m/L+1,但是由于i*L和(i+1)*L不一定是重复子串的第一个开始位置,即i*L不一定对应S[0],所以我们
 尝试调整开始的位置,假设i*L对应于S(0,L)中的某个字符,那么lcp(i*L,(i+1)*L)=m中的m就会比(m/L)*m大一点,这一点就是因为i*L
 不对应S[0],而对应了S(0,L)中的某个字符造成的,这样我们就可以知道,多匹配的这一点长度就对应(i*L对应于S[k] 0<k<L) k到L这一段
 长度,所以应该尝试把i*L向前移动L-m%L个字符(m%L!=0).这样我们就可以求出最大的重复次数。
 加入最多只重复了1次也就是没有重复,那么用上面的方法也可以求得。

 接下来是求最小字典序的步骤,我们在求最大重复次数的时候,保存对应可能的长度L,那么我们可以从sa[1]到sa[n]枚举,
 如果sa[i]和某个长度L能够满足重复次数的要求,那么就得到了答案,枚举中遇到的第一个就是结果,应为sa[1]到sa[n]已经
 按照字典序排序

   */
 #include <cstdio>
 #include <cstring>
 #include <vector>
 #include <algorithm>
 using namespace std;

 ;
 int wa[imax_n],wb[imax_n],wn[imax_n],wv[imax_n];
 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,k,p,*x=wa,*y=wb,*t;
     ;i<m;i++) wn[i]=;
     ;i<n;i++) wn[x[i]=r[i]]++;
     ;i<m;i++) wn[i]+=wn[i-];
     ;i>=;i--) sa[--wn[x[i]]]=i;
     ,p=;p<n;j*=,m=p)
     {
         ,i=n-j;i<n;i++) y[p++]=i;
         ;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
         ;i<n;i++) wv[i]=x[y[i]];
         ;i<m;i++) wn[i]=;
         ;i<n;i++) wn[wv[i]]++;
         ;i<m;i++) wn[i]+=wn[i-];
         ;i>=;i--) sa[--wn[wv[i]]]=y[i];
         ,x[sa[]]=,i=;i<n;i++)
         x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
     }
     return ;
 }
 int rank[imax_n];
 int height[imax_n];
 int a[imax_n];
 char s[imax_n];
 int sa[imax_n];
 int n;
 void calHeight(int *r,int *sa,int n)
 {
     ;
     ;i<=n;i++) rank[sa[i]]=i;
     ;i<n;height[rank[i++]]=k)
     ,j=sa[rank[i]-];r[i+k]==r[j+k];k++);
     return ;
 }

 int min(int a,int b)
 {
     return a<b?a:b;
 }
 ];
 int mm[imax_n];
 void initRMQ(int n,int b[])
 {
     mm[]=-;
     ;i<=n;i++)
     {
         mm[i]=((i&(i-))==)?mm[i-]+:mm[i-];
         dp[i][]=b[i];
     }
     ;j<=mm[n];j++)
     {
         ;i+(<<j)-<=n;i++)
         {
             dp[i][j]=min(dp[i][j-],dp[i+(<<(j-))][j-]);
         }
     }
 }
 int rmq(int x,int y)
 {
     x=rank[x];
     y=rank[y];
     if (x>y)
     {
         int tmp=x;
         x=y;
         y=tmp;
     }
     x++;
     ];
     <<k)+][k]);
 }

 vector<int > vec;

 void Deal()
 {
     n=strlen(s);
     ;i<n;i++)
     {
         a[i]=(int )s[i];
     }
     a[n]=;
     da(a,sa,n+,);
     calHeight(a,sa,n);
     initRMQ(n,height);
     vec.clear();
     ;
     ;l<=n/;l++)  //枚举循环节的长度
     {
         ;i+l<n;i+=l)  //找对应子串S第一个循环节和第二个循环节的位置
         {
             int length=rmq(i,i+l);  //求出重复的次数
             ;
             int newpos=i-(l-length%l);
              && length%l && rmq(newpos,newpos+l)>length) times++;  //尝试更新结果
             if (times>max_times)
             {
                 vec.clear();
                 vec.push_back(l);
                 max_times=times;
             }
             else if (times==max_times)
             {
                 vec.push_back(l);
             }
         }
     }
     sort(vec.begin(),vec.end());
     int cnt=unique(vec.begin(),vec.end())-vec.begin();
     //printf("max_times=%d\n",max_times);
     //for (int i=0;i<cnt;i++)
     //{
     //    printf("length=%d\n",vec[i]);
     //}
     int start,length;
     //printf("size=%d\n",vec.size());

     ;
     ;i<=n && !flag;i++)
     {
         ;j<cnt && !flag;j++)
         {
             )*vec[j])
             {
                 start=sa[i];
                 length=vec[j]*max_times;
                 flag=;
             }
         }
     }
     //printf("start=%d length=%d\n",start,length);
     for (int i=start;i<start+length;i++)
     printf("%c",s[i]);
     printf("\n");
 }

 int main()
 {
     int T;
     ;
     )
     {
         ) break;
         printf("Case %d: ",++t);
         Deal();
     }
     ;
 }

poj3693的更多相关文章

  1. 【poj3693】Maximum repetition substring(后缀数组+RMQ)

    题意:给定一个字符串,求重复次数最多的连续重复子串. 传说中的后缀数组神题,蒟蒻真的调了很久才对啊.感觉对后缀数组和RMQ的模版都不是很熟,导致还是会有很多各种各样的小错误= = 首先,枚举重复子串的 ...

  2. 【poj3693】 Maximum repetition substring

    http://poj.org/problem?id=3693 (题目链接) 题意 给定一个字符串,求重复次数最多的连续重复子串,若存在多组解,输出字典序最小的. Solution 后缀数组论文题,就是 ...

  3. poj3693(后缀数组)

    poj3693 题意 给出一个串,求重复次数最多的连续重复子串,输出字典序最小的. 分析 论文 例8(P21). Sparse-Table算法预处理出任意两个后缀串的LCP. code #includ ...

  4. POJ3693 Maximum repetition substring —— 后缀数组 重复次数最多的连续重复子串

    题目链接:https://vjudge.net/problem/POJ-3693 Maximum repetition substring Time Limit: 1000MS   Memory Li ...

  5. 【SPOJ687&POJ3693】Maximum repetition substring(后缀数组)

    题意: n<=1e5 思路: From http://hzwer.com/6152.html 往后匹配多远 r 用ST表求lcp即可...往前 l 就把串反过来再做一下.. 但是有可能求出来的最 ...

  6. POJ3693 Maximum repetition substring [后缀数组 ST表]

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9458   Acc ...

  7. poj3693 Maximum repetition substring

    题意 给出一个长度为\(n(n\leqslant 100000)\)的串,求一个字典序最小的子串使得它是某个字符串重复\(k\)次得到的,且\(k\)最大 题解 后缀数组论文上的题,跟上一篇uva那个 ...

  8. poj3693之后缀数组

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5946   Accepted: 1799 Description The r ...

  9. Maximum repetition substring (poj3693 后缀数组求重复次数最多的连续重复子串)

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6328   Acc ...

随机推荐

  1. Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存  下面看他们的理解.[size=1.8em]Handler+Runna ...

  2. C#中使用Linq实现全外连接

    每次使用都到处查阅,现在记录下来,备查. var fulljoin = (from s in sampleRegistersjoin t in tensionDatas on new { Beach ...

  3. Java双循环break的用法

    break只跳出当前循环,也就是内循环,如果想跳出外循环有两种办法:1:for(int i = 0;i<9;i++){ //用两个breakfor(int j = 0;j<8;j++){b ...

  4. C++对于大型图片的加载缩放尝试

    Qt对于图片的操作主要集中在这几个类 QImage ,QImageReader ,QPixmap 其中QImage这个类对图片的缩放有几个很不错的技巧,不过对于大图片却并不好使,当我们去看QImage ...

  5. gulp教程之gulp-livereload

    简介: gulp-livereload拯救F5!当监听文件发生变化时,浏览器自动刷新页面.[事实上也不全是完全刷新,例如修改css的时候,不是整个页面刷新,而是将修改的样式植入浏览器,非常方便.]特别 ...

  6. EasyUI combobox 下拉高度自适应

    要指出的是,combobox是继承自combo的,所以,combo的属性也可以被combobox使用,该问题也是这样产生的,知道这个原理,该问题就解决一半了,另一点要指出的是,在easyui中,num ...

  7. 2015-01-16 .Net 中级软件工程师 笔试题

    一 C#方面 1.请简述多线程需要考虑的主要因素 答:1.线程管理 同一核上的两个线程不会以两倍的时长完成,可能需要用两倍再加10 %左右的时间来完成.与一个线程相比较的话,三个线程在同一核上想占用1 ...

  8. sql行列旋转

    一,行转列 先建立测试数据 if OBJECT_ID('week_income') is not null drop table week_income go create table week_in ...

  9. 学习winform第三方界面weiFenLuo.winFormsUI.Docking.dll

    控件dockpanel中提供了几个可用的类, 重要的有两个, 一是DockPanel, 一是DockContent, DockPanel是从panel继承出来的, 用于提供可浮动的dock的子窗口进行 ...

  10. SpringAOP实现(原理)

    AOP原理: AOP分为:JDK动态代理和CGLIB代理 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了.              注 ...