zoukankan      html  css  js  c++  java
  • HihoCoder1407 后缀数组二·重复旋律2

    重复旋律2

    时间限制:5000ms
    单点时限:1000ms
    内存限制:256MB

    描述

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

    旋律可以表示为一段连续的数列,相似的旋律在原数列不可重叠,比如在1 2 3 2 3 2 1 中 2 3 2 出现了一次,2 3 出现了两次,小Hi想知道一段旋律中出现次数至少为两次的旋律最长是多少?

    输入

    第一行一个整数 N。1≤N≤100000

    接下来有 N 个整数,表示每个音的数字。1≤数字≤1000

    输出

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

    样例输入
    8
    1 2 3 2 3 2 3 1
    样例输出
    2

    此题好像不能用单调队列,所以用二分。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=400000;
    int Rank[maxn],cntA[maxn],cntB[maxn],A[maxn],B[maxn];
    int ch[maxn],sa[maxn],tsa[maxn],ht[maxn];
    int ans,N;
    void solve()
    {   
        int i,j;
        for(i=1;i<=N;i++)  cntA[i]=0;
        for(i=1;i<=N;i++)  cntA[ch[i]]++;
        for(i=1;i<=N;i++)  cntA[i]+=cntA[i-1];
        for(i=N;i>=1;i--)  sa[cntA[ch[i]]--]=i;//基数排序 
        Rank[sa[1]]=1;
        for(i=2;i<=N;i++)  
        {
            Rank[sa[i]]=Rank[sa[i-1]];
            if(ch[sa[i]]!=ch[sa[i-1]]) Rank[sa[i]]++;
        }//第一次排序结束。 
        for(int L=1;Rank[sa[N]]<N;L<<=1)
        {
            for(i=0;i<=N;i++) cntA[i]=cntB[i]=0;
            for(i=1;i<=N;i++) cntA[A[i]=Rank[i]]++;
            for(i=1;i<=N;i++) cntB[B[i]=(i+L<=N)?Rank[i+L]:0]++;
            for(i=1;i<=N;i++) cntA[i]+=cntA[i-1];
            for(i=1;i<=N;i++) cntB[i]+=cntB[i-1];
            for(i=N;i>=1;i--) tsa[cntB[B[i]]--]=i;//第二关键字排序 
            for(i=N;i>=1;i--) sa[cntA[A[tsa[i]]]--]=tsa[i];//按第二关键字的顺序给第一关键字排序 
            Rank[sa[1]]=1;
            for(i=2;i<=N;i++)
            {
                Rank[sa[i]]=Rank[sa[i-1]];
                if(A[sa[i]]!=A[sa[i-1]]||B[sa[i]]!=B[sa[i-1]]) Rank[sa[i]]++;//扩散 
            }
        }//排序结束 
        for (i=1,j=0;i<=N;i++)//得到高度 
        {
            if(j) j --;
            while (ch[i+j]==ch[sa[Rank[i]-1]+j]) j++;
            ht[Rank[i]]=j;
        }
    }
    bool check(int x){
        int Min=N,Max=0;
        for(int i=1;i<=N;i++){
            if(ht[i]<x){
                if(Max!=0&&Max-Min>=x)
                        return true;
                Min=Max=sa[i];
                continue;
            }
            Min=min(Min,sa[i]),Max=max(Max,sa[i]);
        }
        if(Max!=0&&Max-Min>=x)
            return true;
        return false;
    }
      
    void getMax()
    {
        int L=0,R=N,mid;
        while(L<=R)//注意这种写法是L<=R 
        {
            mid=(L+R)/2;
            if(check(mid)) {ans=mid;L=mid+1;}
            else R=mid-1;
        }
    }
    int main()
    {
        scanf("%d",&N); 
        for(int i=1;i<=N;i++) scanf("%d",&ch[i]);
        solve();
        getMax();
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    pip install
    自动更新高清电影文件中文名
    csv、excel导入oracle
    02_Jenkins配置任务
    01_Jenkins windows安装
    run_jmeter.py
    02_禅道的基本使用
    01_禅道搭建手册
    01_charles 下载安装(破解版)
    06_Linux常见的命令
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7859251.html
Copyright © 2011-2022 走看看