zoukankan      html  css  js  c++  java
  • 后缀数组练习2:可重叠的k次最长重复子串

    其实和上一题是差不多的,只是在二分check的时候有一些小小的改动

    1468: 后缀数组2:可重叠的k次最长重复子串

    poj3261

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 113  解决: 48
    [提交] [状态] [讨论版] [命题人:admin]

    题目描述

    【问题描述】

    农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天 产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的 牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。 比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。(可重叠的k次最长重复子串)

    【输入格式】

    * Line 1: 两个整数 N,K。

    * Lines 2..N+1: 每行一个整数表示当天的质量值。

    (多组数据)

    【输出格式】

    * Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度

    【样例】
    输入:

    8 2

    1

    2

    3

    2

    3

    2

    3

    1
    输出:

    做法是是和上一题:不可重叠的最长重复子串是差不多的,就是要判断后缀分成若干组,然后判断有没有一个组后缀个数是不小于k的,存在就满足,不存在就不满足
    代码实现,没什么注释,所以我就只放一个版本
     1 /*后将后缀分成若干组。 不同的是,这里要判断的是有没有一个组的后缀个数不小于 k。
     2 如果有,那么存在k 个相同的子串满足条件,否则不存在*/
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<cstdlib>
     6 #include<algorithm>
     7 #include<cmath>
     8 #include<iostream>
     9 using namespace std;
    10 int sa[1000010],Rank[1000010],rsort[1000010];
    11 int a[1000010],cnt[1000010],pos[100010],height[1000010];
    12 bool cmp(int x,int y,int k){return cnt[x]==cnt[y] && cnt[x+k]==cnt[y+k];}
    13 void get_sa(int n,int m) 
    14 {
    15     int k=1,p=0,len;
    16     for(int i=1;i<=n;i++) Rank[i]=a[i];
    17     memset(rsort,0,sizeof(rsort));
    18     for(int i=1;i<=n;i++) rsort[Rank[i]]++;
    19     for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
    20     for(int i=n;i>=1;i--) sa[rsort[Rank[i]]--]=i;
    21     for(int k=1;k<n;k<<=1)
    22     {
    23         len=0;
    24         for(int i=n-k+1;i<=n;i++) pos[++len]=i;
    25         for(int i=1;i<=n;i++) if(sa[i]>k) pos[++len]=sa[i]-k;
    26         for(int i=1;i<=n;i++) cnt[i]=Rank[pos[i]];
    27         memset(rsort,0,sizeof(rsort));
    28         for(int i=1;i<=n;i++) rsort[cnt[i]]++;
    29         for(int i=1;i<=m;i++) rsort[i]+=rsort[i-1];
    30         for(int i=n;i>=1;i--) sa[rsort[cnt[i]]--]=pos[i];
    31         for(int i=1;i<=n;i++) cnt[i]=Rank[i];
    32         p=1; Rank[sa[1]]=1;
    33         for(int i=2;i<=n;i++)
    34         {
    35             if(!cmp(sa[i],sa[i-1],k)) p++;
    36             Rank[sa[i]]=p;
    37         }
    38         if(p==n) break; m=p;
    39     }
    40     a[0]=0; sa[0]=0;
    41 }
    42 void get_he(int n)
    43 {
    44     int j,k=0;
    45     for(int i=1;i<=n;i++)
    46     {
    47         j=sa[Rank[i]-1];
    48         if(k) k--;
    49         while(a[j+k]==a[i+k]) k++;
    50         height[Rank[i]]=k;
    51     }
    52 }
    53 bool check(int mid,int n,int k)
    54 {
    55     int sum=1;
    56     for(int i=2;i<=n;i++)
    57     {
    58         if(height[i]>=mid)/*满足条件*/
    59         {
    60             sum++;/*个数增加*/
    61             if(sum==k) return true;/*如果满足条件就直接返回*/
    62         }
    63         else sum=1;/*否则重新找*/
    64     }
    65     return false;
    66 }
    67 int main() 
    68 {
    69     int n,k;
    70     while(scanf("%d%d",&n,&k)!=EOF)
    71     {
    72         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    73         get_sa(n,1000010); get_he(n);
    74         int l=0,r=n,ans=0;
    75         while(l<=r)
    76         {
    77             int mid=(l+r)/2;
    78             if(check(mid,n,k))
    79             {
    80                 ans=mid;
    81                 l=mid+1;
    82             }
    83             else r=mid-1;
    84         }
    85         printf("%d
    ",ans);
    86     }
    87     return 0;
    88 }
    Tristan Code
  • 相关阅读:
    保持URL不变和数字验证
    centOS ftp key?
    本地环境测试二级域名
    linux 解决You don't have permission to access 问题
    php smarty section loop
    php header Cannot modify header information headers already sent by ... 解决办法
    linux部分命令
    Linux 里面的文件操作权限说明
    用IT网络和安全专业人士视角来裁剪云的定义
    SQL Server 2008 R2炫酷报表"智"作有方
  • 原文地址:https://www.cnblogs.com/Tristanjiang/p/11381437.html
Copyright © 2011-2022 走看看