欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HDU 3518 Boring counting(后缀数组)

程序员文章站 2022-05-11 23:17:35
...
题意:

求出不重叠切出现次数超过两次的子串个数

题解:

后缀数组分组后,判断每组出现的sa最大值和最小值之差是否是大于k就好了,k通过枚举即可


AC代码:

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 2000+50;
char s[MAXN];
int rk[MAXN],h[MAXN],y[MAXN],sa[MAXN],c[MAXN];
inline void SA(int n,int m){
    for(int i=0;i<m;i++) c[i]=0;
    for(int i=0;i<n;i++) c[rk[i]=s[i]]++;
    for(int i=1;i<m;i++) c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--) sa[--c[rk[i]]]=i;
    for(int k=1;k<=n;k<<=1){
        int num=0;
        for(int i=n-k;i<n;i++) y[num++]=i;
        for(int i=0;i<n;i++) if(sa[i]>=k) y[num++]=sa[i]-k;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[rk[i]]++;
        for(int i=1;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--) sa[--c[rk[y[i]]]]=y[i];
        swap(rk,y);
        rk[sa[0]]=0,num=1;
        for(int i=1;i<n;i++)
            rk[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? num-1:num++);
        if(num>=n) break;
        m=num;
    }
}
inline void H(int n){
    for(int i=1;i<=n;i++) rk[sa[i]]=i;
    for(int i=0,k=0;i<n;i++){
        if(k) k--; else k=0;
        int j=sa[rk[i]-1];
        while(s[j+k]==s[i+k]) k++;
        h[rk[i]]=k;
    }
}
inline int solve(int k,int n){
    int ma=0,mi=INF,cnt=0;
    for(int i=1;i<=n;i++){
        if(h[i]<k){
            if(ma-mi>=k) cnt++;
            ma=0,mi=INF;
        }else{
            ma=max(ma,max(sa[i],sa[i-1]));
            mi=min(mi,min(sa[i],sa[i-1]));
        }
    }
    if(ma-mi>=k) cnt++;
    return cnt;
}
int main(){
    while(~scanf("%s",s) && s[0]!='#'){
        int n=strlen(s);
        SA(n+1,'z'+1);
        H(n);
        int ans=0;
        for(int i=1;i<=n/2;i++) ans += solve(i,n);
        printf("%d\n",ans);
    }
    return 0;
}

相关标签: SA