• [USACO06DEC] Milk Patterns


    后缀数组求最长k次重复子串。

    poj 3261 传送门

    洛谷 P2852 传送门

    求完height数组之后倍增答案。

    check的时候枚举height数组。

    如果连续cnt个height都大于等于某长度ans,且cnt不小于题目要求的k次重复,则ans为一个合法答案。

    如果枚举过程中遇到了小于ans的height,则需要重置计数器cnt(初值为1)。

    注意考虑每个数组分别需要开多大。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int n,m,ans;
     7 int s[20005];
     8 int sa[20005],rk[20005];
     9 int h[1000005],tr[1000005];
    10 
    11 int cmp(int x,int y,int k)
    12 {
    13     if(x+k>n||y+k>n)return 0;
    14     return rk[x]==rk[y]&&rk[x+k]==rk[y+k];
    15 }
    16 
    17 void cal()
    18 {
    19     int i,cnt;
    20     for(i=1;i<=n;i++)h[s[i]]++;
    21     for(i=1,cnt=0;i<=1000000;i++)if(h[i])tr[i]=++cnt;
    22     for(i=1;i<=1000000;i++)h[i]+=h[i-1];
    23     for(i=1;i<=n;i++)rk[i]=tr[s[i]],sa[h[s[i]]--]=i;
    24     for(int k=1;cnt!=n;k<<=1)
    25     {
    26         for(i=1;i<=n;i++)h[i]=0;
    27         for(i=1;i<=n;i++)h[rk[i]]++;
    28         for(i=1;i<=n;i++)h[i]+=h[i-1];
    29         for(i=n;i;i--)if(sa[i]>k)tr[sa[i]-k]=h[rk[sa[i]-k]]--;
    30         for(i=1;i<=k;i++)tr[n-i+1]=h[rk[n-i+1]]--;
    31         for(i=1;i<=n;i++)sa[tr[i]]=i;
    32         for(i=1,cnt=0;i<=n;i++)tr[sa[i]]=cmp(sa[i],sa[i-1],k)?cnt:++cnt;
    33         for(i=1;i<=n;i++)rk[i]=tr[i];
    34     }
    35     for(i=1;i<=n;i++)h[i]=0;
    36     for(i=1;i<=n;i++)
    37     {
    38         if(rk[i]==1)continue;
    39         for(int j=max(1,h[rk[i-1]]-1);;j++)
    40         {
    41             if(s[i+j-1]==s[sa[rk[i]-1]+j-1])h[rk[i]]=j;
    42             else break;
    43         }
    44     }
    45 }
    46 
    47 int check(int k)
    48 {
    49     if(k>n)return 0;
    50     int cnt=1;
    51     for(int i=2;i<=n;i++)
    52     {
    53         if(h[i]>=k)cnt++;
    54         else cnt=1;
    55         if(cnt>=m)return 1;
    56     }
    57     return 0;
    58 }
    59 
    60 int main()
    61 {
    62     scanf("%d%d",&n,&m);
    63     for(int i=1;i<=n;i++)scanf("%d",&s[i]);
    64     cal();
    65     for(int i=20;i>=0;i--)
    66         if(check(ans|(1<<i)))ans|=(1<<i);
    67     printf("%d",ans);
    68     return 0;
    69 }
  • 相关阅读:
    bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)
    bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
    spoj 375 Query on a tree(树链剖分,线段树)
    bzoj 2618 2618: [Cqoi2006]凸多边形(半平面交)
    C++中int型与char型相互转换的问题
    408 二进制求和
    407 加一
    斐波那契数列几种算法及时间复杂度分析
    397 Longest Continuous Increasing Subsequence
    376 二叉树的路径和
  • 原文地址:https://www.cnblogs.com/cervusy/p/9715035.html
Copyright © 2020-2023  润新知