• POJ


    http://poj.org/problem?id=3693

    整体思路就是枚举长度L,看长度为L的字符串在s中连续出现了几次。

    既然长度为L的串是重复出现的,那么s[0]…s[L]…s[2*L]…中相邻的两个一定出现在重复的L串中。(并不一定在首尾位置,也可能出现在中间)。

    那么我们求i*L和(i+1)*L的LCP,假设答案为M,那么答案应该是M/L+1(加一是因为i*L~(i+1)*L也是答案)。

    但是这个答案不一定是最优,举一个下面的例子。

    此时M/L+1是3,而正确答案是4。为什么呢?是因为我们枚举的相邻位置不一定在首尾位置。M%L可以理解为末尾多出的字符,我们更可以理解为是前面少了L-M%L个字符,我们把起始位置挪前,挪到(i*L-(L-M%L))位置,同理,(i+1)*L也挪。

    保证字典序最小,我们只要将sa数组从前往后枚举即可。

    这题还学会了这样的复杂度的大小

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <cmath>
      6 #include <vector>
      7 using namespace std;
      8 const int maxn = 1e5+5;
      9 int t1[maxn],t2[maxn],c[maxn];
     10 bool cmp(int *r,int a,int b,int l)
     11 {
     12     return r[a] == r[b] && r[a+l] == r[b+l];
     13 }
     14 void da(int str[],int sa[],int Rank[],int height[],int n,int m)
     15 {
     16     n++;
     17     int i, j, p, *x = t1, *y = t2;
     18     //第一轮基数排序,如果s的最大值很大,可改为快速排序
     19     for(i = 0;i < m;i++)c[i] = 0;
     20     for(i = 0;i < n;i++)c[x[i] = str[i]]++;
     21     for(i = 1;i < m;i++)c[i] += c[i-1];
     22     for(i = n-1;i >= 0;i--)sa[--c[x[i]]] = i;
     23     for(j = 1;j <= n; j <<= 1)
     24     {
     25         p = 0;
     26         //直接利用sa数组排序第二关键字
     27         for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小
     28         for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;
     29         //这样数组y保存的就是按照第二关键字排序的结果
     30         //基数排序第一关键字
     31         for(i = 0; i < m; i++)c[i] = 0;
     32         for(i = 0; i < n; i++)c[x[y[i]]]++;
     33         for(i = 1; i < m;i++)c[i] += c[i-1];
     34         for(i = n-1; i >= 0;i--)sa[--c[x[y[i]]]] = y[i];
     35         //根据sa和x数组计算新的x数组
     36         swap(x,y);
     37         p = 1; x[sa[0]] = 0;
     38         for(i = 1;i < n;i++)
     39             x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     40         if(p >= n)break;
     41         m = p;//下次基数排序的最大值
     42     }
     43     int k = 0;
     44     n--;
     45     for(i = 0;i <= n;i++)Rank[sa[i]] = i;
     46     for(i = 0;i < n;i++)
     47     {
     48         if(k)k--;
     49         j = sa[Rank[i]-1];
     50         while(str[i+k] == str[j+k])k++;
     51         height[Rank[i]] = k;
     52     }
     53 }
     54 int Rank[maxn],height[maxn];
     55 int sa[maxn];
     56 char s[maxn];
     57 int M[maxn][20];
     58 int r[maxn];
     59 void RMQ(int n)
     60 {
     61     for(int i=1;i<=n;i++) M[i][0] = height[i];
     62     for(int j=1;(1<<j)<=n;j++)
     63     {
     64         for(int i=1;(i+(1<<j)-1)<=n;i++)
     65         {
     66             M[i][j] = min(M[i][j-1],M[i+(1<<(j-1))][j-1]);
     67         }
     68     }
     69 }
     70 int RMQ_query(int l,int r)
     71 {
     72     int k = 0;
     73     while((1<<(k+1))<=(r-l+1)) k++;
     74     return min(M[l][k],M[r-(1<<k)+1][k]);
     75 }
     76 int lcp(int a,int b)
     77 {
     78     if(a<0||b<0) return 0;
     79     a = Rank[a],b = Rank[b];
     80     if(a>b) swap(a,b);
     81     return RMQ_query(a+1,b);
     82 }
     83 vector<int> length;
     84 int main()
     85 {
     86     int kase = 0;
     87     while(scanf("%s",s)&&s[0]!='#')
     88     {
     89         int n = strlen(s);
     90         for(int i=0;i<n;i++) r[i] = s[i];
     91         r[n] = 0;
     92         da(r,sa,Rank,height,n,128);
     93         RMQ(n);
     94         int maxv = 0;
     95         length.clear();
     96         printf("Case %d: ",++kase);
     97         for(int l=1;l<n;l++)
     98         {
     99             for(int i=0;i+l<n;i+=l)
    100             {
    101                 int m = lcp(i,i+l);
    102                 int step = m/l+1;    //这必须先除,以免后面移动位置后,M变小了
    103                 int start = i-(l-m%l); //计算挪到的位置
    104                 if(start>=0&&m%l>0)
    105                 {
    106                     if(lcp(start,start+l)>=m)
    107                     {
    108                         step++;
    109                     }
    110                 }
    111                 if(step>maxv)
    112                 {
    113                     maxv = step;
    114                     length.clear();
    115                     length.push_back(l);
    116                 }
    117                 else if(step==maxv)
    118                 {
    119                     length.push_back(l);
    120                 }
    121             }
    122         }
    123       //  printf("%d
    ",maxv);
    124         int start = 0;
    125         int printlen = 0;
    126         int flag = 0;
    127         //枚举排名,保证字典序最小
    128         for(int i=1;i<=n&&!flag;i++)
    129         {
    130             int tt = length.size();
    131             for(int j=0;j<tt;j++)
    132             {
    133                 int l = length[j];
    134                 if(lcp(sa[i],sa[i]+l)>=(maxv-1)*l)
    135                 {
    136                     start = sa[i];
    137                     printlen = l;
    138                     flag = 1;
    139                     break;
    140                 }
    141             }
    142         }
    143        // printf("%d %d %d
    ",start,maxv,printlen);
    144         for(int i=start;i<start+maxv*printlen;i++)
    145         {
    146             printf("%c",s[i]);
    147         }
    148         printf("
    ");
    149     }
    150     return 0;
    151 }
  • 相关阅读:
    Qt4.7.4下单独编译QtWebkit
    CronHowto Community Ubuntu Documentation
    菜鸟学Python(9):给文件添加内容,得到文件信息
    yet another software souring company based on san franciso
    Get Started With Chickenfoot
    Berkeley DB(四) DB Environment
    搭建SSH框架链接Oracle数据库
    Linux下手动编译安装Apache2.x
    Errore HTTP 404.2 Not Found" IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理
    关于二分法中取中间值时向下和向上取整的问题(由大白LA3971想到的)
  • 原文地址:https://www.cnblogs.com/littlepear/p/7347164.html
Copyright © 2020-2023  润新知