POJ 3693 Maximum repetition substring(重复次数最多的连续子串 字典序最小)

来源:互联网 发布:重装系统网络连不上 编辑:程序博客网 时间:2024/04/29 20:46

题意:给你一个字符串(len<=1e5),求重复次数最多的连续重复子串。次数最多的不止一个的话,输出字典序最小的重复子串。



思路:求重复最多好计算,直接题目有做到(点击打开链接)但是要输出一个字典序最小的一开始没弄明白。首先存起来最多次数

能的长度,然后枚举sa数组,取到的第一组,肯定是字典序最小的。但是怎么算取到? 就是LCP(sa[i]+1, sa[i]+1+len) >= 

(ans-1)*a[j],即这一段重复达到了最多次。


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 3e5+5;int t1[maxn], t2[maxn], c[maxn];int ra[maxn], height[maxn];int sa[maxn];char str[maxn];bool cmp(int *r, int a, int b, int l){    return r[a]==r[b]&&r[a+l]==r[b+l];}void da(char str[], int sa[], int ra[], int height[], int n, int m){    n++;    int i, j, p, *x = t1, *y = t2;    for(i = 0; i < m; i++) c[i] = 0;    for(i = 0; i < n; i++) c[x[i]=str[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(j = 1; j <= n; j<<=1)    {        p = 0;        for(i = n-j; i < n; i++) y[p++] = i;        for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;        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]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;        if(p >= n) break;        m = p;    }    int k = 0;    n--;    for(i = 0; i <= n; i++) ra[sa[i]] = i;    for(i = 0; i < n; i++)    {        if(k) k--;        j = sa[ra[i]-1];        while(str[i+k]==str[j+k]) k++;        height[ra[i]] = k;    }}int lcp[maxn][32];void initRMQ(int n){    for(int i = 1; i <= n; i++) lcp[i][0] = height[i];    for(int i = 1; (1<<i) <= n; i++)        for(int j = 1; j+(1<<i)-1 <= n; j++)            lcp[j][i] = min(lcp[j][i-1], lcp[j+(1<<i-1)][i-1]);}//传进去的坐标是从1-nint LCP(int a, int b){    a--, b--;    int l = min(ra[a], ra[b])+1, r = max(ra[a], ra[b]);    int len = r-l+1, i;    for(i = 0; (1<<i) <= len; i++) ;    i--;    return min(lcp[l][i], lcp[r-(1<<i)+1][i]);}int a[maxn];void solve(int n){    int ans = 0, cnt = 0;    for(int l = 1; l <= n; l++)        for(int i = 1; i+l <= n; i+=l)        {            int r = LCP(i, i+l);            if(r/l+1 > ans)            {                ans = r/l+1;                cnt = 0;                a[cnt++] = l;            }            else if (r/l+1 == ans) a[cnt++] = l;            if(i-l+r%l > 0)            {                if(LCP(i-l+r%l, i+r%l)/l+1 > ans)                {                    ans = LCP(i-l+r%l, i+r%l)/l+1;                    cnt = 0;                    a[cnt++] = l;                }                else if(LCP(i-l+r%l, i+r%l)/l+1 == ans) a[cnt++] = l;            }        }    int anss = 0, ansl = n;    for(int i = 1; i <= n; i++)        for(int j = 0; j < cnt; j++)        {            int k = LCP(sa[i]+1, sa[i]+a[j]+1); //千万不能少加1            if(k >= (ans-1)*a[j])            {                anss = sa[i];                ansl = a[j]*ans;                i = n+1;                break;            }        }    for(int i = anss; i < anss+ansl; i++)        printf("%c", str[i]);    puts("");}int main(void){    int ca = 1;    while(~scanf(" %s", str))    {        int len = strlen(str);        if(len == 1 && str[0] == '#')            break;        da(str, sa, ra, height, len, 256);        initRMQ(len);        printf("Case %d: ", ca++);        solve(len);    }    return 0;}



阅读全文
2 0
原创粉丝点击