【后缀数组】[POJ 1743]Musical Theme

来源:互联网 发布:淘宝家具安装价格 编辑:程序博客网 时间:2024/06/07 16:40

题目分析

后缀数组模板题目,我们可以二分一下答案然后我们在构建的每两个数的差所求得的height数组中查找当前连续大于mid的一个区间的pos最小和pos最大值得差值,然后如果这个差值大于了mid我们才认为可以使用,否则会因为有一个节点重叠(相当于每一个差值表示的是一条边,如果刚好相等,那么这两个边的一对端点是重合的)

这里有几点要注意

  1. 后缀数组时最后一个循环要反着
  2. 后缀数组在判断rank的种类是否大于等于n时要在循环底部,不应在条件中否则有可能无法进入循环
  3. 注意统计数量的数组一定要和存放n的数组大小相同

代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 500000;int sa[MAXN+10], r1[MAXN+10], r2[MAXN+10], counter[MAXN+10], height[MAXN+10];void buildsa(int *s, int len, int kind){    for(int i=0;i<=kind;i++) counter[i] = 0;    for(int i=1;i<=len;i++) counter[r1[i]=s[i]]++;    for(int i=0;i<=kind;i++) counter[i] += counter[i-1];    for(int i=len;i>=1;i--) sa[counter[r1[i]]--] = i;    for(int i=1;i<len;i<<=1){        int p = 0;        for(int j=len-i+1; j<=len; j++) r2[++p] = j;        for(int j=1;j<=len;j++)            if(sa[j] > i)                r2[++p] = sa[j] - i;        for(int j=0;j<=kind;j++) counter[j] = 0;        for(int j=1;j<=len;j++) counter[r1[r2[j]]]++;        for(int j=0;j<=kind;j++) counter[j] += counter[j-1];        for(int j=len;j>=1;j--) sa[counter[r1[r2[j]]] --] = r2[j];        swap(r1, r2);        r1[sa[1]] = kind = 1;        for(int j=2;j<=len;j++)            r1[sa[j]] = (r2[sa[j]] == r2[sa[j-1]] && r2[sa[j]+i] == r2[sa[j-1]+i]) ? kind : ++kind;        if(kind >= len) break;    }    int now = 0;    for(int i=1;i<=len;i++){        if(r1[i] == 1){            height[r1[i]] = now = 0;        }else{            now = max(now-1, 0);            int j = sa[r1[i]-1];            while(s[i+now] == s[j+now]) now++;            height[r1[i]] = now;        }    }}bool check(int L, int n){    int Minpos = sa[1], Maxpos = sa[1];    for(int i=2;i<n;i++){        if(height[i] >= L){            Minpos = min(Minpos, sa[i]);            Maxpos = max(Maxpos, sa[i]);        }else{            if(Maxpos - Minpos > L) return true;            Minpos = Maxpos = sa[i];        }    }    return Maxpos - Minpos > L;}int s[MAXN+10];int main(){    int n;    while(scanf("%d", &n), n){        for(int i=1;i<=n;i++)            scanf("%d", &s[i]);        for(int i=2;i<=n;i++)            s[i-1] = s[i] - s[i-1] + 100;        s[n] = 0;        buildsa(s, n-1, 300);        int l = 0, r = n-1, ans=0;        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", 0);        else printf("%d\n", ans+1);    }    return 0;}
0 0
原创粉丝点击