POJ 1743 後綴數組

Musical Theme
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 24507   Accepted: 8259

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.



/*
POJ 1743  後綴數組

給你一串數字,求它們最長的重複(公差相同)子序列,且兩個子序列不相交

表示第一次用後綴數組
我們可以得到
sa[i]:表示排名第i個的首字母位置
Rank[i]:第i個數的排名
Height[i]:sa[i]和sa[i-1]的最長公共前綴


於是我們先求出相鄰兩個數之間的差,然後二分來枚舉長度
如果在當前長度下能找到兩個並且相距合適的就記錄下來
因爲最後得到的是間距的個數  所以ans+1

*/
#include <algorithm>
#include <cmath>
#include <queue>
#include <iostream>
#include <cstring>
#include <map>
#include <cstdio>
#include <vector>
#include <functional>
#define lson (i<<1)
#define rson ((i<<1)|1)
using namespace std;
typedef long long ll;
const int maxn = 20050;

int t1[maxn],t2[maxn],c[maxn];
bool cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b] &&r[l+a] == r[l+b];
}

void get_sa(int str[],int sa[],int Rank[],int height[],int n,int m)
{
    n++;
    int p,*x=t1,*y=t2;
    for(int i = 0; i < m; i++) c[i] = 0;
    for(int i = 0; i < n; i++) c[x[i] = str[i]]++;
    for(int i = 1; i < m; i++) c[i] += c[i-1];
    for(int i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
    for(int j = 1; j <= n; j <<= 1)
    {
        p = 0;
        for(int i = n-j; i < n; i++) y[p++] = i;
        for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;
        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 >= 0; i--)  sa[--c[x[y[i]]]] = y[i];

        swap(x,y);
        p = 1;
        x[sa[0]] = 0;
        for(int i = 1; i < n; i++)
            x[sa[i]] = cmp(y,sa[i-1],sa[i],j)? p-1:p++;
        if(p >= n) break;
        m = p;
    }
    int k = 0;
    n--;
    for(int i = 0; i <= n; i++)
        Rank[sa[i]] = i;
    for(int i = 0; i < n; i++)
    {
        if(k) k--;
        int j = sa[Rank[i]-1];
        while(str[i+k] == str[j+k]) k++;
        height[Rank[i]] = k;
    }

}

int Rank[maxn],height[maxn];
int sa[maxn];
int a[maxn];

bool judge(int len,int n)
{
    for(int i = 2; i <= n; i++)
    {
        if(height[i] < len)
            continue;
        for(int j = i-1; j >= 2; j--)
        {
            if(abs(sa[i] - sa[j]) >= len)
                return true;
            if(height[j] < len)
                break;
        }
    }
    return false;
}

int main()
{
    int n;
    while(scanf("%d",&n) != EOF)
    {

        if(!n)
            break;
        for(int i = 0; i < n; i++)  scanf("%d",&a[i]);
        for(int i = 0; i < n; i++)
            a[i] = a[i+1]-a[i]+90;
        a[n-1] = 0;
        if(n < 10)
        {
            printf("0\n");
            continue;
        }
        get_sa(a,sa,Rank,height,n-1,200);

        int l = 0,r = n;
        int ans ;
        while(l <= r)
        {
            int mid = (l+r) >>1;
            if(judge(mid,n))
            {
                ans = mid;
                l = mid+1;
            }
            else
                r = mid-1;
        }
        if(ans < 4)
            printf("0\n");
        else
            printf("%d\n",ans+1);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章