• hihocoder 1419 重复旋律4


    描述

    小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。小Hi在练习过很多曲子以后发现很多作品中的旋律有重复的部分。

    我们把一段旋律称为(k,l)-重复的,如果它满足由一个长度为l的字符串重复了k次组成。 如旋律abaabaabaaba是(4,3)重复的,因为它由aba重复4次组成。

    小Hi想知道一部作品中k最大的(k,l)-重复旋律。

    解题方法提示

    输入

    一行一个仅包含小写字母的字符串。字符串长度不超过 100000。

    输出

    一行一个整数,表示答案k。

    Sample Input
    babbabaabaabaabab
    Sample Output
    4
    假如循环节长度为L
    如果求出了后缀i和i+L的lcp
    那么重复次数k=lcp(i,i+L)/L+1
    那么O(n^2)的暴力有了,枚举L和i,计算k更新最大值
    但是枚举i可以只枚举L的倍数,算出k
    对于i和i+L,最多只会相差1
    如果最优串的开始位置恰好在L的倍数上,那我们找到的最大的k就是正确答案
    如果不在L的倍数上,那么最优的开始位置肯定在(i-L,i)上
    如果lcp模L有余数,说明前面还需要补上L-lcp%L位,如果可行答案可以加1
    于是可以判断开始位置为i-L+lcp%L与i+lcp%L的lcp
    如果构成重复,那么算出来的
    k=lcp(i-L+lcp%L,i+lcp%L)/L+1=[lcp(i,i+L)/L+1]+1,比开始位置为i要好
    于是复杂度:
    $O(frac{n}{1}+frac{n}{2}+frac{n}{3}+...frac{n}{n})$
    $=O(nlogn)$
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 int n,m,c[200001],x[200001],y[200001],SA[200001],s[200001],rk[200001],h[200001];
     8 int Min[200001][21],Log[200001],ans;
     9 char ch[200001];
    10 void radix_sort()
    11 {int i;
    12   for (i=0;i<=m;i++)
    13     c[i]=0;
    14   for (i=1;i<=n;i++)
    15     c[x[y[i]]]++;
    16   for (i=2;i<=m;i++)
    17     c[i]+=c[i-1];
    18   for (i=n;i>=1;i--)
    19     SA[c[x[y[i]]]--]=y[i];
    20 }
    21 void build_SA()
    22 {int i,j,k,p;
    23   for (i=1;i<=n;i++)
    24     x[i]=s[i],y[i]=i;
    25   m=100000;
    26   radix_sort();
    27   for (k=1;k<=n;k<<=1)
    28     {
    29       p=0;
    30       for (i=n-k+1;i<=n;i++)
    31     y[++p]=i;
    32       for (i=1;i<=n;i++)
    33     if (SA[i]>k) y[++p]=SA[i]-k;
    34       radix_sort();
    35       p=1;swap(x,y);
    36       x[SA[1]]=1;
    37       for (i=2;i<=n;i++)
    38     x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&(y[SA[i]+k]==y[SA[i-1]+k]))?p:++p;
    39       if (p>=n) break;
    40       m=p;
    41     }
    42   for (i=1;i<=n;i++)
    43     rk[SA[i]]=i;
    44   int L=0;
    45   for (i=1;i<=n;i++)
    46     {
    47       if (L>0) L--;
    48       j=SA[rk[i]-1];
    49       while (i+L<=n&&j+L<=n&&(s[j+L]==s[i+L])) L++;
    50       h[rk[i]]=L;
    51     }
    52 }
    53 int rmq(int x,int y)
    54 {
    55   int L=Log[y-x+1];
    56   return min(Min[x][L],Min[y-(1<<L)+1][L]);
    57 }
    58 int lcp(int x,int y)
    59 {
    60   if (rk[x]>rk[y]) swap(x,y);
    61   return rmq(rk[x]+1,rk[y]);
    62 }
    63 int main()
    64 {int i,j,L;
    65   scanf("%s",ch);
    66   n=strlen(ch);
    67   for (i=1;i<=n;i++)
    68     {
    69       s[i]=ch[i-1]-'a'+1;
    70     }
    71   build_SA();
    72   memset(Min,127/2,sizeof(Min));
    73   for (i=1;i<=n;i++)
    74     Min[i][0]=h[i];
    75   Log[1]=0;
    76   for (i=2;i<=n;i++)
    77     Log[i]=Log[i/2]+1;
    78   for (j=1;(1<<j)<=n;j++)
    79     {
    80       for (i=1;i<=n-(1<<j)+1;i++)
    81     Min[i][j]=min(Min[i][j-1],Min[i+(1<<j-1)][j-1]);
    82     }
    83   for (L=1;L<=n;L++)
    84     {
    85       for (i=1;i+L<=n;i+=L)
    86     {
    87       int p=lcp(i,i+L);
    88       ans=max(ans,p/L+1);
    89       if (i-L+p%L>=1)
    90         {
    91           ans=max(ans,lcp(i-L+p%L,i+p%L)/L+1);
    92         }
    93     }
    94     }
    95   printf("%d
    ",ans);
    96 }
  • 相关阅读:
    引用类型构造器
    正则指引量词
    Ajax的XMLHttpRequest对象
    正则指引字符组
    方法可变数量的参数
    不使用XMLHttpRequest实现异步加载:Iframe和script
    可选参数、命名参数
    常量和字段
    正则指引括号
    值类型实例构造器
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8514661.html
Copyright © 2020-2023  润新知