• POJ


    传送门:POJ - 3693  

    题意:给你一个字符串,求重复次数最多的连续重复子串,如果有一样的,取字典序小的字符串。

    题解:

    比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现几次。既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。

    那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀。通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理达到查询为0(1)的复杂度

    设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j+ 1) * L - (L - M % L)的最长公共前缀。即把之前的区间前缀L-M%L即可。

    然后把可能取到最大值的长度L保存,由于 题目要求字典序最小,通过sa数组进行枚举,取到的第一组,肯定是字典序最小的。

    题解的出处:https://blog.csdn.net/acm_cxlove/article/details/7941205 

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<queue>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<cstring>
      7 using namespace std;
      8 
      9 const int maxn = 1e5+10;
     10 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
     11 int rnk[maxn],height[maxn];
     12 char s[maxn];
     13 int r[maxn];
     14 
     15 //sa:字典序中排第i位的起始位置在str中第sa[i]  sa[1~n]为有效值
     16 
     17 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
     18 
     19 //height:字典序排i和i-1的后缀的最长公共前缀  height[2~n]为有效值,第二个到最后一个
     20 
     21 int cmp(int *r,int a,int b,int k)
     22 {
     23     return r[a]==r[b]&&r[a+k]==r[b+k];
     24 }
     25 
     26 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
     27 {
     28     int i,j,p,*x=wa,*y=wb,*t;
     29     for(i=0; i<m; i++)  wsf[i]=0;
     30     for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;
     31     for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
     32     for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;
     33     p=1;
     34     j=1;
     35     for(; p<=n; j*=2,m=p){
     36         for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
     37         for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
     38         for(i=0; i<=n; i++)  wv[i]=x[y[i]];
     39         for(i=0; i<m; i++)  wsf[i]=0;
     40         for(i=0; i<=n; i++)  wsf[wv[i]]++;
     41         for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
     42         for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
     43         swap(x,y);
     44         x[sa[0]]=0;
     45         for(p=1,i=1; i<=n; i++)
     46             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
     47     }
     48 }
     49 
     50 void getheight(int *r,int n)//n为添加0后的总长
     51 {
     52     int i,j,k=0;
     53     for(i=1; i<=n; i++)  rnk[sa[i]]=i;
     54     for(i=0; i<n; i++){
     55         if(k)
     56             k--;
     57         else
     58             k=0;
     59         j=sa[rnk[i]-1];
     60         while(r[i+k]==r[j+k])
     61             k++;
     62         height[rnk[i]]=k;
     63     }
     64 }
     65 
     66 int dp[maxn][40];
     67 
     68 void rmq_init(int n){
     69 
     70     int m=floor(log(n+0.0)/log(2.0));
     71     for(int i=1;i<=n;i++)dp[i][0]=height[i];
     72     for(int j=1;j<=m;j++){
     73         for(int i=n;i;i--){
     74             dp[i][j]=dp[i][j-1];
     75             if(i+(1<<(j-1))<=n){
     76                 dp[i][j]=min(dp[i][j],dp[i+(1<<(j-1))][j-1]);
     77             }
     78         }
     79     }
     80 }
     81 
     82 int rmq(int l,int r){
     83 
     84     int a=rnk[l],b=rnk[r];
     85     if(a>b)swap(a,b);
     86     a++;
     87     int k=floor(log(b-a+1.0)/log(2.0));
     88     return min(dp[a][k],dp[b-(1<<k)+1][k]);
     89 }
     90 
     91 int main()
     92 {
     93     ios::sync_with_stdio(false);
     94     cin.tie(0);
     95     cout.tie(0);
     96     int t=1;
     97     while(cin>>s){
     98         if(s[0]=='#') break;
     99         int len=strlen(s);
    100         for(int i=0;i<len;i++) r[i]=s[i]-'a'+1;
    101         r[len]=0;
    102         getsa(r,sa,len,150);
    103         getheight(r,len);
    104         rmq_init(len);
    105         int ans=0;
    106         int pos=0,p=0;
    107         for(int k=1;k<len;k++){     //枚举长度
    108             for(int i=0;i+k<len;i+=k){  //第i段
    109                 int n=rmq(i,i+k);   //每一段的公共前缀最小值
    110                 n--;
    111                 for(int j=0;j<=k-1;j++){    //枚举每一段的起点
    112                     int now=i-j;
    113                     if((now<0||s[now]!=s[now+k])&&j) break;
    114                     n++;
    115                     int sum=n/k+1;
    116                     if(sum>ans||(sum==ans&&rnk[now]<rnk[pos])){
    117                         ans=sum;
    118                         pos=now;
    119                         p=k;
    120                     }
    121                 }
    122             }
    123         }
    124         cout<<"Case "<<t++<<": ";
    125         if(ans<=1){
    126             char tmp='z';
    127             for(int i=0;i<len;i++) tmp=min(tmp,s[i]);
    128             cout<<tmp<<endl;
    129         }
    130         else{
    131             for(int i=0;i<ans*p;i++){
    132                 cout<<s[i+pos];
    133             }
    134             cout<<endl;
    135         }
    136     }
    137     return 0;
    138 }
  • 相关阅读:
    怎样在Windows下编译OpenVRML
    Virtools脚本语言(VSL)教程 结构
    Virtools脚本语言(VSL)教程 枚举
    基于Python及Wx的离线Blog发布工具Zoundry Raven
    Virtools脚本语言(VSL)教程 使用 GUID
    Khronos关于WebGL最新进展
    【转】在EditPlus中利用正则表达式替换字符串
    Virtools脚本语言(VSL)教程 全局变量bc与ac
    VrmlPad3.0发布
    WebGL样品与演示
  • 原文地址:https://www.cnblogs.com/lilibuxiangtle/p/12635224.html
Copyright © 2020-2023  润新知