现在的位置: 首页 > 综合 > 正文

hdu4691 后缀数组求lcp

2019年04月11日 ⁄ 综合 ⁄ 共 2705字 ⁄ 字号 评论关闭

hdu4691

hdu 是不能用 long long 吗..

还是不会写后缀数组  套学长的模板吧~

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#define INF 0xfffffff
using namespace std;
const int maxn=1e5*2;
/******************************************************************
**  后缀数组 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=128;
    }
    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;
        }
    }
    int d[maxn][20];
    //元素从1编号到n
    void RMQ_init(int A[],int n){
        for (int i=1;i<=n;i++) d[i][0]=A[i];
        for (int j=1;(1<<j)<=n;j++)
            for (int i=1;i+j-1<=n;i++)
                d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
    }
    int RMQ(int L,int R){
        int k=0;
        while ((1<<(k+1))<=R-L+1) k++;
        return min(d[L][k],d[R-(1<<k)+1][k]);
    }
    void LCP_init(){
        RMQ_init(height,n);
    }
    int lcp(int i,int j){
        if (rank[i]>rank[j]) swap(i,j);
        if(rank[i]==rank[j])
            return n-i;
        return RMQ(rank[i]+1,rank[j]);
    }
    void call_fun(char* s){
        init(s);//初始化后缀数组
        build_sa();//构造后缀数组sa
        getHeight();//计算height与rank
        LCP_init();//初始化RMQ
    }
    int LCS(char* s1,char* s2){
        int p,ans;
        int l=strlen(s1);
        p=l;
        s1[l]='$';
        s1[l+1]='\0';
        strcat(s1,s2);
        call_fun(s1);
        ans=0;
        for (int i=2;i<=n;i++)
            if ((sa[i-1]<p&&sa[i]>p)||(sa[i-1]>p&&sa[i]<p)) ans=max(ans,height[i]);
        return ans;
    }
}solver;

char s[maxn];
int main()
{
    //freopen("hdu4691.in","r",stdin);
    while(scanf("%s",s)!=EOF)
    {
        int n;
        scanf("%d",&n);
        solver.call_fun(s);
        __int64 ans_in=n,ans_out=2*n;
        int l1,l2,r1,r2;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&l2,&r2);
            ans_in+=r2-l2;
            if(!i)
            {
                r1=r2,l1=l2;
                ans_out+=r2-l2+1;
                continue;
            }
            int len=min(min(solver.lcp(l2,l1),r2-l2),r1-l1);

            ans_out+=(int)log10(len?len:1)+1+r2-l2-len;
            /*
            if(r2-l2==len)
                ans_out--;
            */
            r1=r2,l1=l2;
        }
        printf("%I64d %I64d\n",ans_in,ans_out);
    }
    return 0;
}

抱歉!评论已关闭.