spoj687 重复次数最多的连续重复子串(后缀数组)

给定一个字符串,求重复次数最多的连续重复子串。
http://www.spoj.com/problems/REPEATS/

枚举可能的循环节长度,不满足单调性,所以不能二分。
每个长度如果可以,一定会选到相邻的L个,于是找到0,L,2*L等等连续的两个,因为间隔L的两个一定是对应位置(画图理解),
找有没有满足s[L*i]== s[L*(i+1)]…每次(n/L)的复杂度,算起来 O(n/1+n/2+n/3+……+n/n)=O(nlogn)。
对于每个,往前找到最大前缀,往后找到最大后缀,加起来就是总长度S S/L+1为个数,如果S不够L长度相当于不符合条件,就是一个也没什么问题咯。
后缀:后缀数组求出后,求这两个位置的(rank【】)之间的所有height最小值(st可搞)
前缀:怎么办???把字符串反过来QAQ

附了几个可能wa的地方,比如1个字母特判。。

/*
枚举可能的循环节长度,不满足单调性,所以不能二分。
每个长度如果可以,一定会选到相邻的L个,于是找到0,L,2*L等等连续的两个,因为间隔L的两个一定是对应位置(画图理解),
找有没有满足s[L*i]== s[L*(i+1)]...每次(n/L)的复杂度,算起来 O(n/1+n/2+n/3+……+n/n)=O(nlogn)。
对于每个,往前找到最大前缀,往后找到最大后缀,加起来就是总长度S S/L+1为个数,如果S不够L长度相当于不符合条件,就是一个也没什么问题咯。
后缀:后缀数组求出后,求这两个位置的(rank【】)之间的所有height最小值(st可搞)
前缀:怎么办???把字符串反过来QAQ
*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 50010;
int  n,ans;
char a[maxn],ab[maxn];
typedef pair<char,int> pii;
int A[maxn],B[maxn],Ab[maxn],Bb[maxn];
int realrank[maxn],k,kb,realrankb[maxn];
pii st[maxn],stb[maxn];
int s[maxn][2],sb[maxn][2];
int h[maxn],hb[maxn];
int C[maxn],D[maxn],Cb[maxn],Db[maxn];
int stmin[maxn][20],stminb[maxn][20];
char ss[2];
void init(){
    for(int i = 1; i <= n ; i++){
        scanf("%s",ss);
        a[i] = ss[0];
    }
    for(int i = 1; i <= n ; i++){
        ab[i] = a[n-i+1];
    }
    for(int i = 1; i <= n ; i++){
        st[i] = make_pair(a[i],i);
        stb[i]= make_pair(ab[i],i);

    }
    sort(st+1,st+1+n);
    sort(stb,stb+1+n);
    k = realrank[st[1].second] = 1;
    kb = realrankb[stb[1].second] = 1;
    for(int i = 2; i <= n ; i++){
        if(st[i].first != st[i-1].first)
            k += 1;
        if(stb[i].first != stb[i-1].first)
            kb += 1;
        realrank[st[i].second] = k;
        realrankb[stb[i].second] = kb;
    }

}

void suffix_array(){
    for(int i = 1; i <= n ; i *= 2){
        for(int j = 0 ; j <= n ; j++)
            A[j] = B[j] = Ab[j] = Bb[j] = 0;
        for(int j = 1;  j <= n ; j++){
            A[s[j][0] = realrank[j]]++;
            Ab[sb[j][0] = realrankb[j]]++;
            if(j+i <= n){
                s[j][1] = realrank[j+i];
                sb[j][1] = realrankb[j+i];
            }
            else    s[j][1] = sb[j][1] = 0;
            B[s[j][1]]++;
            Bb[sb[j][1]]++;
        }
        for(int j = 1; j <= n ;j++)
            A[j] += A[j-1],B[j] += B[j-1],Ab[j] += Ab[j-1],Bb[j] += Bb[j-1];
        for(int j = n ; j >= 1; j--){
            C[B[s[j][1]]] = j;
            Cb[Bb[sb[j][1]]] = j;
            B[s[j][1]]--;
            Bb[sb[j][1]]--;
        }
        for(int j = n ; j >=1; j--){
            D[A[s[C[j]][0]]] = C[j];
            Db[Ab[sb[Cb[j]][0]]] = Cb[j];
            A[s[C[j]][0]]--;
            Ab[sb[Cb[j]][0]]--;
        }
        k = realrank[D[1]] = 1;
        kb = realrankb[Db[1]] = 1;
        for(int j = 2 ; j <= n ; j++){
            if(s[D[j]][0] != s[D[j-1]][0] ||s[D[j]][1] != s[D[j-1]][1])
                k++;
            realrank[D[j]] = k;
            if(sb[Db[j]][0] != sb[Db[j-1]][0] ||sb[Db[j]][1] != sb[Db[j-1]][1])
                kb++;
            realrankb[Db[j]] = kb;
        }
    }
}

void gethigh(){
    int pre = 0,j;
    for(int i = 1; i <= n ; i++){
        if(pre) pre--;
        j = D[realrank[i]-1];
        while(i+pre <= n && j + pre <= n && a[i+pre] == a[j+pre])
            pre++;
        h[realrank[i]] = pre;
    }
    pre = 0;
    for(int i = 1; i <= n ; i++){
        if(pre) pre--;
        j = Db[realrankb[i]-1];
        while(i+pre <= n && j + pre <= n && ab[i+pre] == ab[j+pre])
            pre++;
        hb[realrankb[i]] = pre;
    }
}

int qur(int l,int r){
    if(l > r)   swap(l,r);
     l+=1;
    int len = r-l+1;
    int k = (int)floor(log2(len));
    return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}

int qurb(int l,int r){
   // printf("l = %d  r = %d\n",l,r);
    if(l > r)   swap(l,r);
     l += 1;
    int len = r-l+1;
    int k = (int)floor(log2(len));
    return min(stminb[l][k],stminb[r-(1<<k)+1][k]);
}

void sov(){
    ans = 1;
    for(int L = 1; L <= n; L++){
        //cout <<"L = "<<L<<endl;
        for(int j = L+1; j <= n  ;j += L){
            int cnt = 0;
            if(a[j] == a[j-L]){
                //printf("j = %d\n",j);
                cnt += qur(realrank[j],realrank[j-L]);
                //printf("cnt = %d\n",cnt);
                //cout <<"realrank = "<<realrankb[1]<<endl;
                cnt += qurb(realrankb[n-j+1],realrankb[n-(j-L)+1]);
                //printf("cnt = %d\n",cnt);
                ans = max(ans,(cnt-1)/L+1);
            }
        }
    }
    printf("%d\n",ans);
}

void getst(){
    for(int i = 1 ; i <= n ; i++){
        stmin[i][0] = h[i];
        stminb[i][0] = hb[i];
    }
    for(int i = n ; i >= 1; i--){
        for(int j = 1; (i+(1<<j)-1) <= n ;j++){
            stmin[i][j] = min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
            stminb[i][j] = min(stminb[i][j-1],stminb[i+(1<<(j-1))][j-1]);
        }
    }
}

int main(){
    int T;
    scanf("%d",&T);
    for(int i = 1; i <= T ; i++){
        scanf("%d",&n);
        if(n == 1){
            scanf("%s",ss);
            printf("1\n");
            continue;
        }
        init();
        suffix_array();
        gethigh();
        getst();
        sov();
    }
}
/*
100
4
a
a
a
a

3
a
b
b

1
a

2
a
a

2
a
b
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值