zoukankan      html  css  js  c++  java
  • poj1743 Musical Theme

    地址:http://poj.org/problem?id=1743

    题目:

    Musical Theme
    Time Limit: 1000MS   Memory Limit: 30000K
    Total Submissions: 28675   Accepted: 9674

    Description

    A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of musical timing; but, this programming task is about notes and not timings. 
    Many composers structure their music around a repeating &qout;theme&qout;, which, being a subsequence of an entire melody, is a sequence of integers in our representation. A subsequence of a melody is a theme if it: 
    • is at least five notes long 
    • appears (potentially transposed -- see below) again somewhere else in the piece of music 
    • is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s)

    Transposed means that a constant positive or negative value is added to every note value in the theme subsequence. 
    Given a melody, compute the length (number of notes) of the longest theme. 
    One second time limit for this problem's solutions! 

    Input

    The input contains several test cases. The first line of each test case contains the integer N. The following n integers represent the sequence of notes. 
    The last test case is followed by one zero. 

    Output

    For each test case, the output file should contain a single line with a single integer that represents the length of the longest theme. If there are no themes, output 0.

    Sample Input

    30
    25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
    82 78 74 70 66 67 64 60 65 80
    0
    

    Sample Output

    5

    Hint

    Use scanf instead of cin to reduce the read time.

    Source

    思路:
      论文上的题目,相邻数做差后对数组求后缀数组(注意此时差可能为负数,所以加上100保证非负)
      然后二分长度,check时把height分组判断即可
      

      补个后缀自动机做法:

      先明确几点:

        1.每个状态的代表的是endpos集合相同的后缀集合,记max(s)为状态s的endpos集合中长度最长的后缀,min(x)为最小长度的后缀。

      则endpos集合中的所有后缀都是max(x)的后缀,这说明endpos是长度为一段连续区间的后缀集合。

        2.且endpos(fa[p])是最小的包含endpos(p),且max(fa[p])=min(p)+1。

        3.从root出发的所能到达的状态都是子串,且最长不相交子串就在某一状态的endpos集合中。

      所以对于每个状态记录endpos集合中的最大值最小值,用l[p],r[p]代表。

      拓扑排序后沿反向fa指针dp可以得出每个状态的l[p],r[p]值。

      如果r[p]-l[p]>len[fa[p]]则说明endpos(p)中存在不相交的字符串,长度为min(r[p]-l[p],len[p])。

      对所有状态扫一遍求出最大值即可。

     后缀数组做法:

     1 #include <cstdlib>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 
     6 const int N = 20005;
     7 int sa[N],s[N],wa[N], wb[N], ws[N], wv[N];
     8 int rank[N], height[N];
     9 
    10 bool cmp(int r[], int a, int b, int l)
    11 {
    12     return r[a] == r[b] && r[a+l] == r[b+l];
    13 }
    14 
    15 void da(int r[], int sa[], int n, int m)
    16 {
    17     int i, j, p, *x = wa, *y = wb;
    18     for (i = 0; i < m; ++i) ws[i] = 0;
    19     for (i = 0; i < n; ++i) ws[x[i]=r[i]]++;
    20     for (i = 1; i < m; ++i) ws[i] += ws[i-1];
    21     for (i = n-1; i >= 0; --i) sa[--ws[x[i]]] = i;
    22     for (j = 1, p = 1; p < n; j *= 2, m = p)
    23     {
    24         for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
    25         for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
    26         for (i = 0; i < n; ++i) wv[i] = x[y[i]];
    27         for (i = 0; i < m; ++i) ws[i] = 0;
    28         for (i = 0; i < n; ++i) ws[wv[i]]++;
    29         for (i = 1; i < m; ++i) ws[i] += ws[i-1];
    30         for (i = n-1; i >= 0; --i) sa[--ws[wv[i]]] = y[i];
    31         for (std::swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
    32             x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
    33     }
    34 }
    35 
    36 void calheight(int r[], int sa[], int n)
    37 {
    38     int i, j, k = 0;
    39     for (i = 1; i <= n; ++i) rank[sa[i]] = i;
    40     for (i = 0; i < n; height[rank[i++]] = k)
    41         for (k?k--:0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
    42 }
    43 bool check(int len,int x)
    44 {
    45     int mx=sa[1],mi=sa[1];
    46     for(int i=2;i<=len;i++)
    47     {
    48         if(height[i]<x)
    49         {
    50             if(mx-mi>=x)
    51                 return 1;
    52             mx=mi=sa[i];
    53         }
    54         else
    55         {
    56             mx=std::max(sa[i],mx);
    57             mi=std::min(sa[i],mi);
    58         }
    59     }
    60     return mx-mi>=x;
    61 }
    62 int main()
    63 {
    64     int n;
    65     while(scanf("%d",&n)&&n)
    66     {
    67         int x,ls,len=0;
    68         scanf("%d",&ls);
    69         for(int i=0;i<n-1;i++)
    70             scanf("%d",&x),s[len++]=x-ls+100,ls=x;
    71         s[len]=0;
    72         da(s,sa,len+1,200);
    73         calheight(s,sa,len);
    74         int l=5,r=n/2,ans=0;
    75         while(l<=r)
    76         {
    77             int mid=l+r>>1;
    78             if(check(len,mid-1))
    79                 ans=mid,l=mid+1;
    80             else
    81                 r=mid-1;
    82         }
    83         printf("%d
    ",ans);
    84     }
    85     return 0;
    86 }

     sam做法:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 
     5 using namespace std;
     6 
     7 
     8 
     9 struct SAM
    10 {
    11     static const int MAXN = 20002<<1;//大小为字符串长度两倍
    12     static const int LetterSize = 180;
    13 
    14     int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
    15     int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组
    16     int l[MAXN],r[MAXN];
    17     void init( void)
    18     {
    19         last = tot = 1;
    20         len[1] = 0;
    21         memset(ch,0,sizeof ch);
    22         memset(fa,0,sizeof fa);
    23         memset(cnt,0,sizeof cnt);
    24         memset(l,0x3f3f3f,sizeof l);
    25         memset(r,0,sizeof r);
    26     }
    27 
    28     void add( int x)
    29     {
    30         int p = last, np = last = ++tot;
    31         l[np] = r[np] = len[np] = len[p] + 1, cnt[last] = 1;
    32         while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
    33         if( p == 0)
    34             fa[np] = 1;
    35         else
    36         {
    37             int q = ch[p][x];
    38             if( len[q] == len[p] + 1)
    39                 fa[np] = q;
    40             else
    41             {
    42                 int nq = ++tot;
    43                 memcpy( ch[nq], ch[q], sizeof ch[q]);
    44                 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
    45                 while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
    46             }
    47         }
    48     }
    49 
    50     void toposort( void)
    51     {
    52         for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
    53         for(int i = 1; i <= tot; i++)   sum[len[i]]++;
    54         for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
    55         for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
    56         for(int i = tot; i; i--)
    57         {
    58             l[fa[tp[i]]]=min(l[fa[tp[i]]],l[tp[i]]);
    59             r[fa[tp[i]]]=max(r[fa[tp[i]]],r[tp[i]]);
    60         }
    61         int ans=0;
    62         for(int i = 1; i <= tot; i++)
    63         if(r[i]-l[i]>len[fa[i]])
    64             ans=max(min(r[i]-l[i],len[i]),ans);
    65         if(ans<4) ans=-1;
    66         printf("%d
    ",ans+1);
    67     }
    68 } sam;
    69 
    70 
    71 int main(void)
    72 {
    73     int n,pre;
    74     while(scanf("%d",&n)&&n)
    75     {
    76         sam.init();
    77         scanf("%d",&pre);
    78         for(int i=2,now;i<=n;i++)
    79             scanf("%d",&now),sam.add(now-pre+87),pre=now;
    80         sam.toposort();
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    ReactNative--Flexbox布局
    ReactNative--资源,文章,等等
    ReactNative--坑--no bundle URL present
    ReactNative--StyleSheet样式表
    ReactNative--项目创建及结构分析
    ReactNative--ReactNative简介
    10-4路径文字排版 这一节完全不明白
    10-3区域文字排版
    10-2使用字符调板
    10-1使用文字工具
  • 原文地址:https://www.cnblogs.com/weeping/p/6648714.html
Copyright © 2011-2022 走看看