POJ

来源:互联网 发布:淘宝宝贝拍照灯光选择 编辑:程序博客网 时间:2024/05/29 19:44

Musical Theme

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

3025 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 1882 78 74 70 66 67 64 60 65 800

Sample Output

5

Hint

Use scanf instead of cin to reduce the read time.

Source

LouTiancheng@POJ


题意:求不重叠的最长公共子串长度


解题思路:后缀数组,这里用来保存后缀数组模板!后缀数组的学习推荐论文  所有的模板都出自这篇论文  后缀数组——处理字符串的有力工具



解题时,主要用到三个数组,说明如下:


SA数组,即后缀数组,SA[i]记录的是,所有后缀按字典序排好序后,排第i的后缀的第一个字符的下标为SA[i]。

注意下标从0开始!即SA[0]代表字典序最小的那个后缀的第一个字符的下标!


rk数组,即rank排名数组,rk[i]记录的是,所有后缀按字典序排好序后,第一个字符的下标为i的后缀的排名为rk[i]。与SA为互逆关系.

下标从0开始!


height数组,height[i]记录的是SA[i]与SA[i-1]所代表的两个后缀的最长公共前缀的长度。

下标从1开始!


注意!字符串的下标也是从0开始。即第一个字符的下标为0.


为了统一代码和编码方便,我们在计算时,会在字符串末尾补一个0,即把字符串结束符也算进去,这样计算出来的结果更统一!SA[0]永远等于字符串长度。height[1]永远等于0!详见代码例子!

注意由于加了一个0,现在SA[0]~SA[N]都是有意义的,而不是SA[N-1],rk,height同理。


关于这道题,因为要不重叠,所以不能直接使用height数组,我们要二分长度,然后用height数组判断即可。


#include <iostream>#include <deque>#include <stdio.h>#include <map>#include <string>#include <algorithm>#include <vector>#include <math.h>#include <stack>#include <queue>#include <set>using namespace std;typedef long long int ll;const int MAXN = 100000; //用DC3要开三倍大小int wa[MAXN], wb[MAXN], wv[MAXN], JS[MAXN]; //计算SA用的辅助数组int rk[MAXN], height[MAXN], SA[MAXN]; //三个常用数组/***后缀数组倍增解法***/int cmp(int *r, int a, int b, int l){    return r[a] == r[b] && r[a + l] == r[b + l];}void DA(int *r, int *SA, int n, int m){    int i, j, p, *x = wa, *y = wb, *t;    for (i = 0; i < m; i++)        JS[i] = 0;    for (i = 0; i < n; i++)        JS[x[i] = r[i]]++;    for (i = 1; i < m; i++)        JS[i] += JS[i - 1];    for (i = n - 1; i >= 0; i--)        SA[--JS[x[i]]] = i;    for (j = 1, p = 1; p < n; j *= 2, m = p)    {        for (p = 0, i = n - j; i < n; i++)            y[p++] = i;        for (i = 0; i < n; i++)            if (SA[i] >= j)                y[p++] = SA[i] - j;        for (i = 0; i < n; i++)            wv[i] = x[y[i]];        for (i = 0; i < m; i++)            JS[i] = 0;        for (i = 0; i < n; i++)            JS[wv[i]]++;        for (i = 1; i < m; i++)            JS[i] += JS[i - 1];        for (i = n - 1; i >= 0; i--)            SA[--JS[wv[i]]] = y[i];        for (t = x, x = y, y = t, 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++;    }    return;}/*******************//***后缀数组DC3解法***/#define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb))#define G(x) ((x) < tb ? (x)*3 + 1 : ((x)-tb) * 3 + 2)int c0(int *r, int a, int b){    return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];}int c12(int k, int *r, int a, int b){    if (k == 2)        return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);    else        return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];}void sort(int *r, int *a, int *b, int n, int m){    int i;    for (i = 0; i < n; i++)        wv[i] = r[a[i]];    for (i = 0; i < m; i++)        JS[i] = 0;    for (i = 0; i < n; i++)        JS[wv[i]]++;    for (i = 1; i < m; i++)        JS[i] += JS[i - 1];    for (i = n - 1; i >= 0; i--)        b[--JS[wv[i]]] = a[i];    return;}void DC3(int *r, int *SA, int n, int m){    int i, j, *rn = r + n, *SAn = SA + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;    r[n] = r[n + 1] = 0;    for (i = 0; i < n; i++)        if (i % 3 != 0)            wa[tbc++] = i;    sort(r + 2, wa, wb, tbc, m);    sort(r + 1, wb, wa, tbc, m);    sort(r, wa, wb, tbc, m);    for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)        rn[F(wb[i])] = c0(r, wb[i - 1], wb[i]) ? p - 1 : p++;    if (p < tbc)        DC3(rn, SAn, tbc, p);    else        for (i = 0; i < tbc; i++)            SAn[rn[i]] = i;    for (i = 0; i < tbc; i++)        if (SAn[i] < tb)            wb[ta++] = SAn[i] * 3;    if (n % 3 == 1)        wb[ta++] = n - 1;    sort(r, wb, wa, ta, m);    for (i = 0; i < tbc; i++)        wv[wb[i] = G(SAn[i])] = i;    for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)        SA[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];    for (; i < ta; p++)        SA[p] = wa[i++];    for (; j < tbc; p++)        SA[p] = wb[j++];    return;}/***********************///计算rank和height数组void calheight(int *r, int *SA, int n){    //  memset(height,0,sizeof(height));    //  memset(rk,0,sizeof(rk));    int i, j, k = 0;    for (i = 1; i <= n; i++)        rk[SA[i]] = i;    for (i = 0; i < n; height[rk[i++]] = k)        for (k ? k-- : 0, j = SA[rk[i] - 1]; r[i + k] == r[j + k]; k++)            ;}int N;         //字符串长度int str[MAXN]; //主字符串bool judge(int len){    int l = SA[1];    int r = SA[1];    for (int i = 2; i <= N; i++)    {        if (height[i] < len)        {            l = SA[i];            r = SA[i];            continue;        }        r = max(r, SA[i]);        l = min(l, SA[i]);        if (r - l > len)            return true;    }    return false;}int main(){    while (~scanf("%d", &N))    {        if (N == 0)            break;        for (int i = 0; i < N; i++)            scanf("%d", &str[i]);        for (int i = 0; i < N - 1; i++)            str[i] = str[i + 1] - str[i] + 90;        str[--N] = 0; //必须要末尾补0!!!!!        DA(str, SA, N + 1, 200);//N是没有补0的大小,算SA时要把末尾0计算进去,所以要N+1        calheight(str, SA, N);//计算height时不用末尾0        int l = 0;        int r = N;        int m;        int ans = 0;        while (l < r)        {            m = (l + r) / 2;            if (judge(m))            {                ans = m;                l = m + 1;            }            else                r = m;        }        if (ans < 4)            printf("0\n");        else            printf("%d\n", ans + 1);    }    return 0;}


原创粉丝点击