POJ 1743 Musical Theme(二分+后缀数组)

来源:互联网 发布:it技术论坛 知乎 编辑:程序博客网 时间:2024/04/28 03:35

题意:

求不重叠的最长相同变化的子串的最长长度,比如1 2 3 4 5 6 7 8 9 10,最长长度为5,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的

思路:

男人八题之一,然而poj上a了都一万多了。。。。
思路在论文里面讲的很清楚了(其实应该是一个区间最大sa减去最小sa大于k,而不是大于等于,dicuss有人说了这个问题,我也是这么认为的,不过因为poj数据太水导致都能过)。这里讲一个坑点,就是表示前后的差值的时候会出现负数,要手动加上88,而因为都是差值且数值都是1-88,所以m最大也不会超过N

错误及反思:

数据很水,第一次交的有个地方其实不对但是也算我ac了

代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N = 20100;int sa[N],rak[N],height[N];int arr[N];void construct(const int *s,int n,int m) {    static int t1[N],t2[N],c[N];    int *x = t1,*y = t2;    int i,j,k,p,l;    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];        std::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;    }    for (i = 0; i < n; ++ i) rak[sa[i]] = i;    for (i = 0,l = 0; i < n; ++ i) {        if (rak[i]) {            j = sa[rak[i] - 1];            while (s[i + l] == s[j + l]) l++;            height[rak[i]] = l;            if (l) l--;        }    }}bool judge(int x,int n){    for(int i=2;i<=n;i++)    {        int minn=n,maxn=-1;        while(height[i]>=x)        {            minn=min(minn,sa[i-1]);            minn=min(minn,sa[i]);            maxn=max(maxn,sa[i-1]);            maxn=max(maxn,sa[i]);            i++;        }        if(maxn-minn>x) return true;    }    return false;}int main(){    int n;    while(scanf("%d",&n)&&n)    {        for(int i=0;i<n;i++)            scanf("%d",&arr[i]);        for(int i=0;i<n-1;i++)            arr[i]=arr[i+1]-arr[i]+88;        construct(arr,n,20100);        int l=0,r=n-1;        while(l+1<r)        {            int m=(l+r)>>1;            if(judge(m,n-1)) l=m;            else r=m;        }        if(l+1<5) printf("0\n");        else printf("%d\n",l+1);    }}
原创粉丝点击