zoukankan      html  css  js  c++  java
  • [poj1743]Musical Theme(后缀数组)

    题意:不可重叠最长重复子串

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

        1.长度至少为5个音符。(只需最后加个判定即可,无影响)

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

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

    解题关键:二分答案,转化为存在性判定,后缀数组问题的套路解法,不要对k用了两次感到奇怪,因为第二次是用来判重的

    思想:利用height值对后缀进行分组

     1 #include <cstdlib>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 #include<iostream>
     6 #include<cmath>
     7 #define inf 0x3f3f3f3f
     8 using namespace std;
     9 const int N=200005;
    10 int wa[N],wb[N],wv[N],wc[N];
    11 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
    12 void make_sa(int *r,int *sa,int n,int m){
    13     int i,j,p,*x=wa,*y=wb;
    14     for(i=0;i<m;i++) wc[i]=0;
    15     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
    16     for(i=1;i<m;i++) wc[i]+=wc[i-1];
    17     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
    18     for(j=1,p=1;p<n;j*=2,m=p){
    19         for(p=0,i=n-j;i<n;i++) y[p++]=i;
    20         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
    21         for(i=0;i<n;i++) wv[i]=x[y[i]];
    22         for(i=0;i<m;i++) wc[i]=0;
    23         for(i=0;i<n;i++) wc[wv[i]]++;
    24         for(i=1;i<m;i++) wc[i]+=wc[i-1];
    25         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
    26         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    27     }
    28     return;
    29 }
    30 int rank1[N],height[N],sa[N];
    31 void make_height(int *r,int *sa,int n){
    32     int i,j,k=0;
    33     for(i=1;i<=n;i++) rank1[sa[i]]=i;
    34     for(i=0;i<n;height[rank1[i++]]=k)
    35         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
    36     return;
    37 }
    38 
    39 
    40 int r[N],a[N];
    41 int n,k;
    42 bool check(int k){//二分公共子串长度,将大于等于k的个数的组分别进行判定,利用height值对后缀进行分组,存在即可 
    43     int maxn,minn;
    44     maxn=-inf,minn=inf;
    45     for(int i=2;i<=n;i++){
    46         if(height[i]>=k){
    47             minn=min(min(sa[i],sa[i-1]),minn);//lcp一定在height中
    48             maxn=max(max(sa[i],sa[i-1]),maxn);
    49             if(maxn-minn>k) return 1;//保证不重复 
    50         }else        maxn=-inf,minn=inf;
    51     }
    52     return 0;
    53 }
    54 int erfen(int l,int r){
    55     while(l<r){
    56         int mid=(l+r+1)>>1;
    57         if(check(mid)) l=mid;
    58         else r=mid-1;
    59     }
    60     l++;//消除差分的影响 
    61     if(l<5) l=0;
    62     return l;
    63 }
    64 
    65 int main(){
    66     ios::sync_with_stdio(0);
    67     cin.tie(0);
    68     cout.tie(0);
    69     while(cin>>n&&n){
    70         for(int i=0;i<n;i++) cin>>a[i];
    71         for(int i=0;i<n-1;i++) r[i]=a[i+1]-a[i]+100;
    72         r[--n]=0;
    73         make_sa(r, sa, n+1,220);
    74         make_height(r, sa, n);
    75         int ans=erfen(0,n);
    76         cout<<ans<<"
    ";
    77     }
    78     return 0;
    79 }
  • 相关阅读:
    hdoj-1005-Number Sequences
    FOJ-1058-粗心的物理学家
    程序设计第三次作业附加 代码规范
    简单数论
    FOJ-1001-Duplicate Pair
    链表初尝试-链表的构建与输出-指针
    函数递归简单题-hdoj-2044 2018-一只小蜜蜂 母牛的故事
    电路与电子学-第一章直流电路分析方法小概括
    DFS回溯-函数递归-xiaoz triangles
    进制转换 hdoj-2031
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7350519.html
Copyright © 2011-2022 走看看