zoukankan      html  css  js  c++  java
  • 字符串 后缀数组(可重叠的k 次最长重复子串)poj 3261

    开始用起了后缀数组这种高级的东西,虽然细节方面是勉强看懂了,但是能运用好就行

    要是有做这套题的朋友实在是不得其解的话,去看看这篇论文吧。。

    IOI2009 国家集训队论文后缀数组罗穗骞

    height数组当中存了从第一名到最后一名的公共前缀的长度

    height 数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。那么对于j 和k,不妨设
    rank[j]<rank[k],则有以下性质:
    suffix(j) 和suffix(k) 的最长公共前缀为height[rank[j]+1],height[rank[j]+2], height[rank[j]+3], … ,height[rank[k]]中的最小值。

    那么此题我们可以二分枚举其中的答案。

    代码如下:

    View Code
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<cmath>
     7 using std::sort;
     8 int const M = 1001000;
     9 int const N = 20100;
    10 int rank[N],wb[M],wv[M],ws[M],height[N],num[N],sa[N];
    11 int n,k;
    12 int cmp(int *r,int a,int b,int l)
    13 {
    14     return r[a]==r[b]&&r[a+l]==r[b+l];
    15 }
    16 void da(int *r,int *sa,int n,int m)
    17 {
    18     int i,j,p,*x=rank,*y=wb,*t;
    19     for(i=0; i<m; i++) ws[i]=0;
    20     for(i=0; i<n; i++) ws[x[i]=r[i]]++;
    21     for(i=1; i<m; i++) ws[i]+=ws[i-1];
    22     for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i;
    23     for(j=1,p=1; p<n; j*=2,m=p)
    24     {
    25         for(p=0,i=n-j; i<n; i++) y[p++]=i;
    26         for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
    27         for(i=0; i<n; i++) wv[i]=x[y[i]];
    28         for(i=0; i<m; i++) ws[i]=0;
    29         for(i=0; i<n; i++) ws[wv[i]]++;
    30         for(i=1; i<m; i++) ws[i]+=ws[i-1];
    31         for(i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i];
    32         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
    33             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    34     }
    35     return;
    36 }
    37 
    38 void calheight(int *r,int *sa,int n)
    39 {
    40     int i,j,k=0;
    41     for(i=1; i<=n; i++) rank[sa[i]]=i;
    42     for(i=0; i<n; height[rank[i++]]=k)
    43         for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
    44     return;
    45 }
    46 bool check(int len)
    47 {
    48      int tot=0;
    49      for(int i=2;i<=n;i++)
    50      {
    51          if(height[i]<len)tot=0;
    52          else
    53          {
    54             tot++;
    55             if(tot==k-1)return true;
    56          }
    57      }
    58      return false;
    59 }
    60 int main()
    61 {
    62     while(~scanf("%d %d",&n,&k))
    63     {
    64           for(int i=0;i<n;i++)
    65           {
    66               scanf("%d",&num[i]);
    67           }
    68           da(num,sa,n+1,M);
    69           calheight(num,sa,n);
    70           int ans=0;
    71           int l=0,r=n;
    72           while(l<=r)
    73           {
    74                 int m=(l+r)>>1;
    75                 if(check(m))
    76                    l=m+1,ans=m;
    77                 else
    78                    r=m-1;
    79           }
    80           printf("%d\n",ans);
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    线性表---顺序表&链表
    C++——虚函数表——typedef指向函数的指针
    C++——继承与多态
    C++——动态内存分配new--delete
    C++——模板---函数模板---类模板
    C++——指针---指向数组的指针---指向字符串的指针--指向函数的指针--指针的指针--指针的引用
    C++——this指针
    C++——运算符的重载---以成员函数方式重载---以友元函数方式重载
    C++——友元函数--友元类——friend关键字
    Ubuntu环境下实现WireShark抓取HTTPS
  • 原文地址:https://www.cnblogs.com/nuoyan2010/p/2991783.html
Copyright © 2011-2022 走看看