acdream OJ 1430 SETI 后缀数组

又是孙大大的模板..

本来想在有什么方法在O(n)里搞出来  结果就是发明了WA数组..

听了讲解才知道怎么做   然后终于由WA变成PE了了了了....

话说少了个回车比赛会扣分吗?应该扣吧..


这道题给height数组分段算  好像有道题和这个很像

height[i]>=k 并且连着的算一段   如果这一段有至少一个符合条件(不重叠)的  那么ans++

我这里是用暴力写的  写完以后想想好像是单调栈啊!

不过竟然暴力过了就不写了 -  -


#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=3e5*2+10;
/******************************************************************
**  后缀数组 Suffix Array
**  INIT:solver.call_fun(char* s);
**  CALL: solver.lcp(int i,int j); //后缀i与后缀j的最长公共前缀
**  SP_USE: solver.LCS(char *s1,char* s2); //最长公共字串
******************************************************************/
struct SuffixArray{
    int r[maxn];
    int sa[maxn],rank[maxn],height[maxn];
    int t[maxn],t2[maxn],c[maxn],n;
    int m;//模板长度
    void init(char* s){
        n=strlen(s);
        for (int i=0;i<n;i++) r[i]=int(s[i]);
        m=300;
    }
    int cmp(int *r,int a,int b,int l){
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    /**
    字符要先转化为正整数
    待排序的字符串放在r[]数组中,从r[0]到r[n-1],长度为n,且最大值小于m。
    所有的r[i]都大于0,r[n]无意义算法中置0
    函数结束后,结果放在sa[]数组中(名次从1..n),从sa[1]到sa[n]。s[0]无意义
    **/
    void build_sa(){
        int i,k,p,*x=t,*y=t2;
        r[n++]=0;
        for (i=0;i<m;i++) c[i]=0;
        for (i=0;i<n;i++) c[x[i]=r[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,p=1;k<n;k*=2,m=p){
            for (p=0,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];
            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],k)?p-1:p++;
        }
        n--;
    }
    /**
    height[2..n]:height[i]保存的是lcp(sa[i],sa[i-1])
    rank[0..n-1]:rank[i]保存的是原串中suffix[i]的名次
    **/
    void getHeight(){
        int i,j,k=0;
        for (i=1;i<=n;i++) rank[sa[i]]=i;
        for (i=0;i<n;i++){
            if (k) k--;
            j=sa[rank[i]-1];
            while (r[i+k]==r[j+k]) k++;
            height[rank[i]]=k;
        }
    }
    void call_fun(char* s){
        init(s);//初始化后缀数组
        build_sa();//构造后缀数组sa
        getHeight();//计算height与rank
        /*
        for(int i=0;i<=n;i++)
            printf("%d\t",i);
        puts("SA:");
        for(int i=0;i<=n;i++)
            printf("%d\t",sa[i]);
        puts("");
        puts("RK:");
        for(int i=0;i<=n;i++)
            printf("%d\t",rank[i]);
        puts("");
        puts("H:");
        for(int i=0;i<=n;i++)
            printf("%d\t",height[i]);
        puts("");
        */
    }

    int calc(int k)
    {
        int mx=sa[1],mn=sa[1],sz=0,ret=0;
        for(int i=2;i<=n;i++)
        {
            if(height[i]>=k)
            {
                sz++;
                mx=max(sa[i],mx);
                mn=min(sa[i],mn);
            }
            else
            {
                //printf("%d:<%d to %d>\n",i,mn,mx);
                if(mx-mn>=k)
                    ret++;
                mx=sa[i];
                mn=sa[i];
                sz=0;
            }
        }
        if(sz&&mx-mn>=k)
            ret++;
        //printf("ret:%d %d\n\n",k,ret);
        return ret;
    }

    void run(char *s)
    {
        call_fun(s);
        long long ans=0;
        int len=n/2;
        for(int i=1;i<=len;i++)
            ans+=calc(i);
        printf("%lld\n",ans);
    }
}solver;

char s[10010];
int main()
{
    scanf("%s",s);
    //char s[]="abbbbbbaaaa"; ///5
    //char s[]="aaa"; ///1
    //char s[]="abacabacaba"; ///15
    solver.run(s);
    return 0
}



你可能感兴趣的:(数据结构,字符串,ACM,后缀自动机)