poj 1743 求不可重叠最长字符串

来源:互联网 发布:淘宝联盟结算规则 编辑:程序博客网 时间:2024/05/16 01:31

http://hi.baidu.com/blackstar08/blog/item/6909b391bb308a83a977a429.html

题目大意:

给定一段音乐乐谱,其中的音符用数字表示出来( 范围 [ 1,88 ] ),要求的是这段乐谱的主旋律。所谓的主旋律,就是满足以下三点要求的一段子串:
1、音符的数目至少为5;
2、重复出现在乐谱中的另一个地方;

3、不相互重叠;

而且平移也算重复,比如1 2 3 4 5和6 7 8 9 10是算作重复的,后面的是前面的平移5,然后不互相重叠意思两个主旋律得隔开,比如1 2 3 4 5 6 7 8 9 10

1 2 3 4 5和6 7 8 9 10是紧挨着的,所以不算

解题思路:《后缀数组——处理字符串的有力工具》,求不可重叠最长字符串, 运算时,因为是用计数排序,所以要保证每个数为正。

把后一个旋律减去前一个旋律,要是主旋律重复出现,那么后面减响铃前面形成的间隔差是相同的,那么不可重叠的最长字符串就至少是4了。

然后用后缀数组来处理,详细见上述论文描述。最长公共前缀不小于k的两个后缀,一定是在同一组,按2分来求,逐渐缩小范围。当长度为k时,判断一个组里面sa的最大值和最小值之差是否大于等于k。满足则说明这个k是存在的。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int const maxn = 20010;int n, str[maxn], sa[maxn], rank[maxn], height[maxn], wx[maxn], wy[maxn], c[maxn];inline bool cmp(int *s, int a, int b, int l);void suffix(int *s, int *sa, int n, int m);void cal_height(int *s, int *sa, int n);bool check(int index, int n);int main(){        while(true)    {        scanf("%d", &n);        if(n == 0)            break;        n--;        int a, b;        scanf("%d", &a);        for(int i = 0; i < n; i++)        {            scanf("%d", &b);            str[i] = b - a + 100;            a = b;        }        str[n] = 0;        suffix(str, sa, n + 1, 189);        cal_height(str, sa, n);              int l = 1, r = n, ans = -1;        while(l <= r)        {            int mid = (l + r) >> 1;            if(check(mid, n + 1))            {                ans = mid;                l = mid + 1;            }            else                r = mid - 1;        }        if(ans >= 4)            printf("%d\n", ans + 1);        else            printf("0\n");    }        return 0;}inline bool cmp(int *s, int a, int b, int l){    return s[a] == s[b] && s[a + l] == s[b + l];}void suffix(int *s, int *sa, int n, int m){    int *x = wx;    int *y = wy;    int *t, index = 0;    for(int i = 0; i < m; i++)        c[i] = 0;    for(int i = 0; i < n; i++)        c[x[i] = s[i]]++;    for(int i = 1; i < m; i++)        c[i] += c[i-1];    for(int i = n - 1; i >= 0; i--)        sa[--c[s[i]]] = i;    for(int j = 1; j <= n; j *= 2, m = index)    {        index = 0;        for(int i = n - j; i < n; i++)            y[index++] = i;        for(int i = 0; i < n; i++)        {            if(sa[i] >= j)                y[index++] = 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];        t = x; x = y; y = t;        x[sa[0]] = rank[sa[0]]= 0;        index = 1;        for(int i = 1; i < n; i++)        {            if(j * 2 < n)                x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? index - 1 : index++;            else                rank[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? index - 1 : index++;        }    }    }void cal_height(int *s, int *sa, int n){    int k = 0;    for(int i = 0; i < n; height[rank[i++]] = k)    {        if(k != 0)            k--;        for(int j = sa[rank[i] - 1]; s[i + k] == s[j + k]; k++);    }}bool check(int index, int n){    int minv, maxv;    minv = maxv = sa[1];    for(int i = 2; i <= n; i++)    {        if(height[i] >= index && i != n)        {            minv = min(minv, sa[i]);            maxv = max(maxv, sa[i]);        }        else        {            if(maxv - minv >= index)                return true;            minv = maxv = sa[i];        }    }    return false;}



原创粉丝点击