zoukankan      html  css  js  c++  java
  • 【hihoCoder 1419】重复旋律4

    Description

    小 Hi 平时的一大兴趣爱好就是演奏钢琴。 我们知道一个音乐旋律被表示为长度为 N的数构成的数列。 
    小 Hi 在练习过很多曲子以后发现很多作品中的旋律有重复的部分。 
    我们把一段旋律称为( k , l )-重复的, 如果它满足由一个长度为 l 的字符串重复了 k 次组成。 如旋律 abaabaabaaba 是(4,3)重复的, 因为它由 aba 重复 4 次组成。 
    小 Hi 想知道一部作品中 k 最大的(k,l)-重复旋律。

    Input

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

    Output

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

    Sample Input

    babbabaabaabaabab

    Sample Output

    4

    Hint

    数据约束: 
    30%的数据 N<=1000 
    70%的数据 N<=10000 
    100%的数据 N<=100000

    题解:

    容易想到判断循环结延伸的长度就是i和i+k(k为循环结长度)的lcp,求两个后缀的lcp显然就是高度数组对应的一段的最小值

    RMQ维护即可 

    接着就是难点,我们不必枚举每一个位置,只需枚举k的倍数

    但是可能存在情况:使得i+l i+l+1  (1<=l<=k)使得次数大了1

    但是显然我们可以O1的找出这个位置的答案 即为 lcp(i-k+R%k,i+R%k)  R为lcp(i,i+k) 可以画个图理解下

    R%k是求出lcp不能形成新循环的多出来的一段 那么我们就直接求lcp即可

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 using namespace std;
     8 const int N=100005;
     9 int s[N],n=0,rk[N],sa[N],tmp[N],k;char S[N];
    10 bool comp(int i,int j){
    11     if(rk[i]!=rk[j])return rk[i]<rk[j];
    12     int ri=i+k<=n?rk[i+k]:-1;
    13     int rj=j+k<=n?rk[j+k]:-1;
    14     return ri<rj;
    15 }
    16 void Getsa(){
    17     for(int i=1;i<=n;i++){
    18         sa[i]=i;rk[i]=s[i];
    19     }
    20     for(k=1;k<=n;k<<=1){
    21         sort(sa+1,sa+n+1,comp);
    22         tmp[sa[0]]=0;
    23         for(int i=1;i<=n;i++)tmp[sa[i]]=tmp[sa[i-1]]+comp(sa[i-1],sa[i]);
    24         for(int i=1;i<=n;i++)rk[i]=tmp[i];
    25     }
    26 }
    27 int high[N];
    28 void Gethight(){
    29     int j,h=0;
    30     for(int i=1;i<=n;i++){
    31         j=sa[rk[i]-1];
    32         if(h)h--;
    33         for(;i+h<=n && j+h<=n;h++)if(s[i+h]!=s[j+h])break;
    34         high[rk[i]-1]=h;
    35     }
    36 }
    37 int f[N][25];
    38 int query(int l,int r){
    39     int k=log(r-l+1)/log(2);
    40     return min(f[l][k],f[r-(1<<k)+1][k]);
    41 }
    42 void prework(){
    43     int to;
    44     for(int i=1;i<=n;i++)f[i][0]=high[i];
    45     for(int j=1;j<=22;j++){
    46         for(int i=1;i<=n-(1<<j)+1;i++){
    47             to=i+(1<<(j-1));
    48            if(f[i][j-1]<f[to][j-1])f[i][j]=f[i][j-1];
    49             else f[i][j]=f[to][j-1];
    50         }
    51     }
    52 }
    53 int lcp(int x,int y){
    54     if(rk[x]>rk[y])swap(x,y);
    55     return query(rk[x],rk[y]-1);
    56 }
    57 int main()
    58 {
    59     //freopen("pp.in","r",stdin);
    60     scanf("%s",S);
    61     for(int i=0,sz=strlen(S);i<sz;i++)
    62         s[++n]=S[i]-'a'+1;
    63     Getsa();
    64     Gethight();
    65     prework();
    66     int ans=0,to;
    67     for(int g=1;g<=n;g++){
    68         for(int i=1;i+g<=n;i+=g){
    69             to=lcp(i,i+g);
    70             ans=max(ans,to/g+1);
    71             if(i-g+(to%g)>=1){
    72                 ans=max(lcp(i-g+to%g,i+to%g)/g+1,ans);
    73             }
    74         }
    75     }
    76     printf("%d
    ",ans);
    77     return 0;
    78 }
  • 相关阅读:
    java 23种设计模式 深入理解
    ORACLE 一条记录 某字段值以';'拆分为多条记录
    rabbitmq集群故障恢复
    ORACLE 时间加减操作
    Asp.net MVC Razor输出字符串方法(js中嵌入razor)
    C# ToString() 数据格式
    DOM的整个知识体系
    EF 连接模式
    EF Code First 数据库连接方式
    使用border实现提示框的
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7157329.html
Copyright © 2011-2022 走看看