• POJ 3261 出现至少K次的可重叠最长子串


    题意就是给一列数字,求最长的一个子串,并且满足子串在原数串中出现至少K次,子串可以重叠。

    解法是将问题转为判定性问题,二分子串的长度,判定是否满足重复至少K次。判定方法是经典的根据子串长度将Height数组分组,看某一分组是否至少含有K个元素。

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 #include <string>
     5 #include <string.h>
     6 #include <stdio.h>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <set>
    11 #include <cmath>
    12 #include <ctime>
    13 #include <cassert>
    14 #include <sstream>
    15 using namespace std;
    16 
    17 const int N=2e6+110;
    18 
    19 int sa[N];
    20 int t1[N],t2[N],c[N];
    21 int rk[N],height[N];
    22 
    23 inline int cmp(int *r,int a,int b,int l){
    24     return r[a]==r[b]&&r[a+l]==r[b+l];
    25 }
    26 int s[N];
    27 void calcSA (int *s,int n,int m) {
    28     int i,j,p,*x=t1,*y=t2;
    29     for(i=0;i<m;i++)c[i]=0;
    30     for(i=0;i<n;i++)c[x[i]=s[i]]++;
    31     for(i=1;i<m;i++)c[i]+=c[i-1];
    32     for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    33     for(j=1;j<=n;j<<=1){
    34         p=0;
    35         for(i=n-j;i<n;i++)y[p++]=i;
    36         for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
    37         for(i=0;i<m;i++)c[i]=0;
    38         for(i=0;i<n;i++)c[x[y[i]]]++;
    39         for(i=1;i<m;i++)c[i]+=c[i-1];
    40         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
    41         swap(x,y);
    42         p=1;x[sa[0]]=0;
    43         for(i=1;i<n;i++)
    44             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    45         if(p>=n)break;
    46         m=p;
    47     }
    48 }
    49 
    50 void calcHeight(int *s,int n) {
    51     int i,j,k=0;
    52     for(i=0;i<=n;i++)rk[sa[i]]=i;
    53     for(i=0;i<n;i++){
    54         if(k)k--; // h[i]>=h[i-1]-1
    55         j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位
    56         while(s[i+k]==s[j+k])k++; // 暴力计算lcp
    57         height[rk[i]]=k;
    58     }
    59 }
    60 
    61 
    62 bool ok(int n,int m,int k) {
    63     int cnt=1;
    64     for (int i=1;i<=n;i++) {
    65         if (height[i]<m) {
    66             cnt=1;
    67         }
    68         else {
    69             cnt++;
    70             if (cnt>=k) return true;
    71         }
    72     }
    73     return false;
    74 }
    75 int main () {
    76     int n,k;
    77     while (scanf("%d %d",&n,&k)!=EOF) {
    78         int mx=0;
    79         for (int i=0;i<n;i++) {
    80             scanf("%d",s+i);
    81             mx=max(mx,s[i]);
    82         }
    83         s[n]=0;
    84         calcSA(s,n+1,mx+10);
    85         calcHeight(s,n);
    86         int l=0,r=n,ret=0;
    87         while (l<=r) {
    88             int m=(l+r)>>1;
    89             if (ok(n,m,k)) {
    90                 ret=m;
    91                 l=m+1;
    92             }
    93             else r=m-1;
    94         }
    95         cout<<ret<<endl;
    96     }
    97     return 0;
    98 }
  • 相关阅读:
    三:Redis连接池、JedisPool详解、Redisi分布式
    vmware workstation14永久激活密钥分享
    人工智能二:TensorFlow环境搭建
    消息队列二:关于消息队列
    消息队列一:为什么需要消息队列(MQ)?
    java基础进阶一:String源码和String常量池
    人工智能一:Al学习路线
    Python学习二:词典基础详解
    Python学习一:序列基础详解
    什么是Hive
  • 原文地址:https://www.cnblogs.com/micrari/p/4820403.html
Copyright © 2020-2023  润新知