zoukankan      html  css  js  c++  java
  • poj 3693 后缀数组

    链接:点我

      1 /*
      2  * POJ 3693 Maximum repetition substring
      3  * 先穷举长度L,然后求长度为L的子串最多能连续出现多少次
      4  * 既然长度为L的串重复出现,那么str[0],str[l],str[2*l]……中肯定有两个连续的出现在字符串中。
      5 那么就枚举连续的两个,然后从这两个字符前后匹配,看最多能匹配多远。
      6 即以str[i*l],str[i*l+l]前后匹配,这里是通过查询suffix(i*l),suffix(i*l+l)的最长公共前缀
      7 通过rank值能找到i*l,与i*l+l的排名,我们要查询的是这段区间的height的最小值,通过RMQ预处理
      8 达到查询为0(1)的复杂度,
      9  设LCP长度为M, 则答案显然为M / L + 1, 但这不一定是最好的, 因为答案的首尾不一定再我们枚举的位置上. 我的解决方法是, 我们考虑M % L的值的意义, 我们可以认为是后面多了M % L个字符, 但是我们更可以想成前面少了(L - M % L)个字符! 所以我们求后缀j * L - (L - M % L)与后缀(j + 1) * L - (L - M % L)的最长公共前缀。
     10 即把之前的区间前缀L-M%L即可。
     11 然后把可能取到最大值的长度L保存,由于 题目要求字典序最小,通过sa数组进行枚举,取到的第一组,肯定是字典序最小的。
     12  */
     13 
     14 #include <iostream>
     15 #include <stdio.h>
     16 #include <algorithm>
     17 #include <string.h>
     18 using namespace std;
     19 const int MAXN=100010;
     20 
     21 /*
     22  * 倍增算法求后缀数组
     23  */
     24 int sa[MAXN];
     25 int t1[MAXN],t2[MAXN],c[MAXN];
     26 int rank[MAXN],height[MAXN];
     27 void build_sa(int s[],int n,int m)
     28 {
     29     int i,j,p,*x=t1,*y=t2;
     30     for(i=0;i<m;i++)c[i]=0;
     31     for(i=0;i<n;i++)c[x[i]=s[i]]++;
     32     for(i=1;i<m;i++)c[i]+=c[i-1];
     33     for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
     34     for(j=1;j<=n;j<<=1)
     35     {
     36         p=0;
     37         for(i=n-j;i<n;i++)y[p++]=i;
     38         for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
     39         for(i=0;i<m;i++)c[i]=0;
     40         for(i=0;i<n;i++)c[x[y[i]]]++;
     41         for(i=1;i<m;i++)c[i]+=c[i-1];
     42         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
     43         swap(x,y);
     44         p=1;x[sa[0]]=0;
     45         for(i=1;i<n;i++)
     46             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
     47         if(p>=n)break;
     48         m=p;
     49     }
     50 }
     51 void getHeight(int s[],int n)
     52 {
     53     int i,j,k=0;
     54     for(i=0;i<=n;i++)rank[sa[i]]=i;
     55     for(i=0;i<n;i++)
     56     {
     57         if(k)k--;
     58         j=sa[rank[i]-1];
     59         while(s[i+k]==s[j+k])k++;
     60         height[rank[i]]=k;
     61     }
     62 }
     63 int mm[MAXN];
     64 int best[20][MAXN];
     65 void initRMQ(int n)
     66 {
     67     mm[0]=-1;
     68     for(int i=1;i<=n;i++)
     69         mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
     70     for(int i=1;i<=n;i++)best[0][i]=i;
     71     for(int i=1;i<=mm[n];i++)
     72         for(int j=1;j+(1<<i)-1<=n;j++)
     73         {
     74             int a=best[i-1][j];
     75             int b=best[i-1][j+(1<<(i-1))];
     76             if(height[a]<height[b])best[i][j]=a;
     77             else best[i][j]=b;
     78         }
     79 }
     80 int askRMQ(int a,int b)
     81 {
     82     int t;
     83     t=mm[b-a+1];
     84     b-=(1<<t)-1;
     85     a=best[t][a];b=best[t][b];
     86     return height[a]<height[b]?a:b;
     87 }
     88 int lcp(int a,int b)
     89 {
     90     a=rank[a];b=rank[b];
     91     if(a>b)swap(a,b);
     92     return height[askRMQ(a+1,b)];
     93 }
     94 char str[MAXN];
     95 int r[MAXN];
     96 int a[MAXN];
     97 int main()
     98 {
     99     //freopen("in.txt","r",stdin);
    100     //freopen("out.txt","w",stdout);
    101     int iCase=0;
    102     while(scanf("%s",str)==1)
    103     {
    104         if(strcmp(str,"#")==0)break;
    105         iCase++;
    106         int n=strlen(str);
    107         for(int i=0;i<=n;i++)r[i]=str[i];
    108         build_sa(r,n+1,128);
    109         getHeight(r,n);
    110         initRMQ(n);
    111         int cnt=0,mmax=0;
    112         for(int l=1;l<n;l++)
    113         {
    114             for(int i=0;i+l<n;i+=l)
    115             {
    116                 int t1=lcp(i,i+l);
    117                 int step=t1/l+1;
    118                 int  k=i-(l-t1%l);
    119                 if(k>=0&&t1%l)
    120                 {
    121                     if(lcp(k,k+l)>=t1)step++;
    122                 }
    123                 if(step>mmax)
    124                 {
    125                     mmax=step;
    126                     cnt=0;
    127                     a[cnt++]=l;
    128                 }
    129                 else if(step==mmax)
    130                     a[cnt++]=l;
    131             }
    132         }
    133         int len=-1,st;
    134         for(int i=1;i<=n&&len==-1;i++)
    135         {
    136             for(int j=0;j<cnt;j++)
    137             {
    138                 int l=a[j];
    139                 if(lcp(sa[i],sa[i]+l)>=(mmax-1)*l)
    140                 {
    141                     len=l;
    142                     st=sa[i];
    143                     break;
    144                 }
    145             }
    146         }
    147         str[st+len*mmax]=0;
    148         printf("Case %d: %s
    ",iCase,str+st);
    149     }
    150     return 0;
    151 }
  • 相关阅读:
    js 基于函数伪造的方式实现继承
    js 创建List<Map> 这种格式的集合
    微信get post请求到微信服务器 模版 素材操作
    微信开发学习 问题1: 网页授权问题 “该连接无法访问” 解决方法
    Jackson 高性能的JSON处理 ObjectMapper
    baseDao 使用spring3+hibernate4方式
    PropertiesUtil 读取配置文件工具类
    C语言(函数)学习之strstr strcasestr
    命令行选项解析函数(C语言):getopt()和getopt_long()
    AE插件开发的一些总结
  • 原文地址:https://www.cnblogs.com/cnblogs321114287/p/4493968.html
Copyright © 2011-2022 走看看