• Musical Theme


    题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:

        1.长度至少为5个音符。

        2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)

        3.重复出现的同一主题不能有公共部分。

    /*
        改了三个小时,还是没有改出来,WA到挺了。
        说一下解题过程吧。
        二分答案,然后按照公共前缀长度是否大于等于mid分组,若有一组中的间距大于mid,则说明找到了一组符合要求的。 
    */
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define N 51000
    using namespace std;
    int ch[N],s[N],sa[N],rank[N],height[N],t1[N],t2[N],c[N];
    bool cmp(int *y,int a,int b,int k){
        return y[a]==y[b]&&y[a+k]==y[b+k];
    }
    void DA(int n,int m){
        int *x=t1,*y=t2;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[i]=s[i]]++;
        for(int i=1;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;~i;i--) sa[--c[x[i]]]=i;
        for(int k=1,p=0;k<=n;k*=2,m=p,p=0){
            for(int i=n-k;i<n;i++) y[p++]=i;
            for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            for(int i=0;i<m;i++) c[i]=0;
            for(int i=0;i<n;i++) c[x[y[i]]]++;
            for(int i=1;i<m;i++) c[i]+=c[i-1];
            for(int i=n-1;~i;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);p=1;x[sa[0]]=0;
            for(int i=1;i<n;i++)
                if(cmp(y,sa[i],sa[i-1],k)) x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            if(p>=n) break;
        }
        for(int i=0;i<n;i++) rank[sa[i]]=i;
    }
    void get_ht(int n){
        for(int i=1,k=0;i<n;height[rank[i++]]=k){
            int j=sa[rank[i]-1];k=k?k-1:0;
            while(s[j+k]==s[i+k]) k++;
        }
    }
    bool check(int n,int mid){
        int minn=n+1,maxn=-1;
        for(int i=1;i<=n;i++){
            if(height[i]<mid){
                if(maxn-minn>mid) return true;
                minn=n+1;maxn=-1;
            }
            minn=min(minn,sa[i]);
            maxn=max(maxn,sa[i]);
        }
        if(maxn-minn>mid) return true;
        return false;
    }
    void CL(){
        memset(s,0,sizeof(s));
        memset(sa,0,sizeof(sa));
        memset(rank,0,sizeof(rank));
        memset(height,0,sizeof(height));
        memset(t1,0,sizeof(t1));
        memset(t2,0,sizeof(t2));
        memset(ch,0,sizeof(ch));
        memset(c,0,sizeof(c));
    }
    int main(){
        int n;
        while(scanf("%d",&n)&&n){
            CL();
            for(int i=0;i<n;i++)
                scanf("%d",&ch[i]);
            for(int i=0;i<n-1;i++)
                s[i]=ch[i+1]-ch[i]+100;
            s[n-1]=0;
            if(n==1){printf("0
    ");continue;}
            DA(n+1,400);get_ht(n);
            int l=0,r=n,ans;
            while(l<=r){
                int mid=l+r>>1;
                if(check(n,mid)) l=mid+1,ans=mid;
                else r=mid-1;
            }
            ans++;
            ans=ans<5?0:ans;
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    怎样检测数据类型
    怎样理解函数参数的传递
    怎样在微信H5中点击直接跳转到公众号
    怎样启动和关闭nginx服务器
    怎样测试nginx.conf配置文件的正确性
    怎样查找/搜索文件
    怎样创建用户组并添加用户进用户组
    怎样查看Nginx版本号
    怎样写一个Hello World!
    怎样理解基本类型(原始类型)的数据和引用类型的数据
  • 原文地址:https://www.cnblogs.com/harden/p/6539724.html
Copyright © 2020-2023  润新知