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;
}
时间: 2024-09-27 23:16:57

Musical Theme - poj 1743(求最大不重叠重复子串)的相关文章

poj 1743 最长不重叠重复子串 后缀数组+lcp+二分

题比较容易读懂,但是建模需动点脑子: 一个子串加常数形成的子串认为跟子串相同,求最长不重叠重复子串 题目中说 is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s) 意味着不能重叠,举个例子 1, 2,3,  52, 53,54 1,2, 3和 52, 53,54满足题意,差值为51 枚举差值肯定不行------看了题解明白的:: 后项减去前一项得到: 1,1,1,49,1,1  

poj 1961 (求字符串中的重复子串)

Sample Input 3aaa12aabaabaabaab0Sample Output Test case #12 23 3 Test case #22 2 //aa有2个a6 2 //aabaab有2个aab9 312 4 0  1  2 3 4 5 6 7 8 9 10 11 a  a b a a b  a a b a a b     的next数组为-1 0 1 0 1 2 3 4 5 6 7 8 9 1 #include<stdio.h> 2 #include<iostrea

POJ - 1743 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 music

poj 1743 后缀数组 求最长不重叠重复子串

题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题. “主题”是整个音符序列的一个子串,它需要满足如下条件:1.长度至少为5个音符2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值.)3.重复出现的同一主题不能有公共部分. 链接:点我先转化成相邻两项的差值,然后就是找不可重叠重复子串.做法就是二分答案LEN然后根据height值进行分组 第一道后缀数组题,测了一下模板

【hiho】120 后缀数组一&#183;重复旋律2【字符串--后缀数组--最长不可重叠重复子串问题】

传送门:后缀数组一·重复旋律2 题意 最长可重叠重复子串问题 思路 二分答案,转化成判定问题. 看看能不能找出不重叠的重复子串.对于每一组,我们检查这些后缀对应的sa值(也就是后缀起点在原串中的位置i).如果max{sa} - min{sa} >= k,那么就说明我们能找出一组不重叠的重复子串 AC Code #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; c

POJ 题目1743 Musical Theme(后缀数组,求一个串中最长不重叠重复子串)

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21826   Accepted: 7467 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

POJ 1743 Musical Theme (后缀数组,求最长不重叠重复子串)

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

POJ 1743 - Musical Theme 最长不重叠重复子串

题意:    给出一列数据,问你其中重复的最长连续子串的长度    但是有要求:        1. 长度至少为 5 .        2. 两串可以不相等,但两串每个对应位置的数字相减差值固定 (即相同变化) 分析:    因为子串变化相同,故可先把原数组前后相减, 则求出差值数组的最长重复子串的长度再 +1 就是答案.        最长重复子串的长度:        使用后缀数组.        先将问题变为判定是否存在长度为 x 的重复子串,再用二分寻找答案.        用 heig

POJ 1743 (后缀数组+不重叠最长重复子串)

题目链接: http://poj.org/problem?id=1743 题目大意:楼教主の男人八题orz.一篇钢琴谱,每个旋律的值都在1~88以内.琴谱的某段会变调,也就是说某段的数可以加减一个旋律范围的值.问这个谱子内最长不重叠的重复部分大小. 解题思路: 网上题解已经泛滥的题.很多细节都被先辈大神总结了. 在当年后缀数组还不是热门的时候,这题确实是神题. 首先对于旋律变调的处理: 比如123,123,ans=3. 变调之后:456,123,ans=0?不ans=3. 所以不能使用旋律的初始