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

来源:互联网 发布:解决mac下迅雷慢 编辑:程序博客网 时间:2024/06/06 06:41

后缀数组模板题
照着kuangbin大神的模板敲得~~
/*
* POJ 1743 Musical Theme
* 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。
* “主题”是整个音符序列的一个子串,它需要满足如下条件:
* 1.长度至少为5个音符
* 2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。)
* 3.重复出现的同一主题不能有公共部分。
*
* 先转化成相邻两项的差值,然后就是找不可重叠重复子串。
* 做法就是二分答案LEN
* 然后根据height值进行分组
*/
分析:
这里写图片描述

#include<cstdio>#include<algorithm>using namespace std;#define rep(i,s,t) for(int i=(s);i<(t);i++)#define per(i,t,s) for(int i=(t);i>=(s);i--)const int INF = 1e9 + 9;const int N = 20000 + 9;/********************倍增算法*后缀数组模板*******************************//**suffix array*倍增算法  O(n*logn)*待排序数组长度为n,放在0~n-1中,在最后面补一个0*build_sa( ,n+1, );//注意是n+1;*getHeight(,n);*例如:*n   = 8;*num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0*rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值*sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值**/int sa[N], t1[N], t2[N], c[N], rk[N], height[N];void build_sa (int s[], int n, int m) {    int i, k, p, *x = t1, *y = t2;    for (i = 0; i < m; i++) c[i] = 0;    for (i = 0; i < n; i++) c[x[i] = s[i]]++;    for (i = 1; i < m; i++) c[i] += c[i - 1];    for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;    for (k = 1; k <= n; k <<= 1) {        p = 0;        for (i = n - k; i < n; i++) y[p++] = i;        for (i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i] - k;        for (i = 0; i < m; i++) c[i] = 0;        for (i = 0; i < n; i++) c[x[y[i]]]++;        for (i = 1; i < m; i++) c[i] += c[i - 1];        for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];        swap (x, y);        p = 1;        x[sa[0]] = 0;        for (i = 1; i < n; i++)            x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p ++;        if (p >= n) break;        m = p;    }}void getHeight (int s[], int n) {    int i, j, k = 0;    for (i = 0; i <= n; i++) rk[sa[i]] = i;    for (i = 0; i < n; i++) {        if (k) k--;        j = sa[rk[i] - 1];        while (s[i + k] == s[j + k]) k++;        height[rk[i]] = k;    }}/********************************************************************************/int s[N];bool ok (int n, int k) {    int Max = sa[1], Min = sa[1];    for (int i = 2; i <= n; i++) {        if (height[i] < k) Max = Min = sa[i];        else {            if (sa[i] < Min) Min = sa[i];            if (sa[i] > Max) Max = sa[i];            if (Max - Min > k) return 1;        }    }    return 0;}int main() {    //freopen ("f.txt", "r", stdin);    int n;    while (~scanf ("%d", &n) && n) {        rep (i, 0, n) scanf ("%d", &s[i]);        per (i, n - 1, 1) s[i] = s[i] - s[i - 1] + 90;        //   rep(i,0,n)printf("%d ",s[i]);printf("\n");        n--;        rep (i, 0, n) s[i] = s[i + 1];        s[n] = 0;        //     rep(i,0,n)printf("%d ",s[i]);printf("\n");        build_sa (s, n + 1, 200);        getHeight (s, n);        int l = 1, r = n / 2;        while (l < r) {            int mid = l + (r - l + 1) / 2;            if (ok (n, mid) ) l = mid;            else r = mid - 1;        }        if (l < 4) puts ("0");        else printf ("%d\n", l + 1);    }    return 0;}
0 0
原创粉丝点击