Musical Theme - poj 1743(求最大不重叠重复子串)

题目大意:

* 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。 * “主题”是整个音符序列的一个子串,它需要满足如下条件: * 1.长度至少为5个音符 * 2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。) * 3.重复出现的同一主题不能有公共部分。

 

分析:也是看的论文才做的这道题,学了4天的后缀数组,终于A掉一道题了,啥也不说了,都是眼泪(怎么做可以看看论文,说的很详细)。

 

代码如下:

===============================================================================================================

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int MAXN = 2e4+7;
const int BaseNum = 90;

struct SuffixArr
{
    int text[MAXN], tempx[MAXN], tempy[MAXN];
    int sum[MAXN], rank[MAXN], sa[MAXN], heigh[MAXN];
    int *x, *y, N, MaxId;

    void Insert(int mus[], int len)
    {
        N = len, MaxId = 200;
        x = tempx, y=tempy;

        for(int i=0; i<N; i++)
        {
            x[i] = text[i] = mus[i];
            y[i] = i;
        }
    }
    void BaseSort()
    {
        for(int i=0; i<MaxId; i++)
            sum[i] = 0;
        for(int i=0; i<N; i++)
            sum[ x[ y[i] ] ] += 1;
        for(int i=1; i<MaxId; i++)
            sum[i] += sum[i-1];
        for(int i=N-1; i>=0; i--)
            sa[ --sum[ x[ y[i] ] ] ] = y[i];
    }
    bool OK(int i, int len)
    {
        if(sa[i]+len>N || sa[i-1]+len>N)
            return false;
        if(y[sa[i]] != y[sa[i-1]] || y[sa[i]+len] != y[sa[i-1]+len])
            return false;

        return true;
    }
    void Build_Sa()
    {
        BaseSort();

        for(int len=1; len<N; len<<=1)
        {
            int id = 0;

            for(int i=N-len; i<N; i++)
                y[id++] = i;
            for(int i=0; i<N; i++)if(sa[i]>=len)
                y[id++] = sa[i] - len;

            BaseSort();
            swap(x, y);

            x[ sa[0] ] = id = 0;

            for(int i=1; i<N; i++)
            {
                if(OK(i, len) == true)
                    x[ sa[i] ] = id;
                else
                    x[ sa[i] ] = ++id;
            }

            MaxId = id+1;

            if(MaxId >= N)break;
        }
    }
    void GetHeight()
    {
        for(int i=0; i<N; i++)
            rank[ sa[i] ] = i;

        for(int k=0,i=0; i<N; i++)
        {
            if(!rank[i])
            {
                k = heigh[0] = 0;
                continue;
            }
            if(k)k--;

            int pre = sa[ rank[i]-1 ];

            while(text[pre+k] == text[i+k])
                k++;
            heigh[rank[i]] = k;
        }
    }
};

struct SuffixArr suf;
int music[MAXN];

bool Find(int k)
{
    int Min, Max;

    Min = Max = suf.sa[0];

    for(int i=1; i<suf.N; i++)
    {
        if(suf.heigh[i] < k)
            Min = Max = suf.sa[i];
        else
        {
            Min = min(Min, suf.sa[i]);
            Max = max(Max, suf.sa[i]);

            if(Max-Min > k)
                return true;
        }
    }

    return false;
}

int main()
{
    int i, N;

    while(scanf("%d", &N), N)
    {
        for(i=0; i<N; i++)
        {
            scanf("%d", &music[i]);
            if(i)music[i-1] = music[i-1]-music[i]+BaseNum;
        }
        music[N-1] = 0;

        suf.Insert(music, N);
        suf.Build_Sa();
        suf.GetHeight();

        int L=4, R=N/2, ans=-1;

        while(L <= R)
        {
            int Mid = (L+R)>>1;

            if(Find(Mid) == true)
            {
                L = Mid + 1;
                ans = Mid;
            }
            else
                R = Mid - 1;
        }

        printf("%d\n", ans+1);
    }

    return 0;
}

 

posted @ 2015-09-04 12:41  无忧望月  阅读(145)  评论(0编辑  收藏  举报
levels of contents