poj3415 Common Substrings (后缀数组+单调栈)

来源:互联网 发布:极右势力的网络保护伞 编辑:程序博客网 时间:2024/04/29 06:26

论文上提了一些思路,参考大牛的方法,勉强理解一些。。。
神题目,攒人品

#include<cstdio>#include<iostream>#include<algorithm>#include<string>#include<cstring>using namespace std;#define LL long long#define cl(a,b) memset(a,b,size(a))const int maxn=200010;/*lcp与论文模板height数组下标偏差1*/int n,k;int rank[maxn],tmp[maxn],sa[maxn],lcp[maxn];int cmp(int i,int j){    if(rank[i]!=rank[j])return rank[i]<rank[j];    int ri=i+k<=n?rank[i+k]:-1;    int rj=j+k<=n?rank[j+k]:-1;    return ri<rj;}void getSa(char *s){    n=strlen(s);    for(int i=0;i<=n;i++){        sa[i]=i;        rank[i]=i<n?s[i]:-1;    }    for(k=1;k<=n;k<<=1){        sort(sa,sa+n+1,cmp);        tmp[sa[0]]=0;        for(int i=1;i<=n;i++){            tmp[sa[i]]=tmp[sa[i-1]]+cmp(sa[i-1],sa[i]);        }        for(int i=0;i<=n;i++)rank[i]=tmp[i];    }}void getLcp(char *s){   // n=strlen(s);    for(int i=0;i<=n;i++)rank[sa[i]]=i;    int h=0;    lcp[0]=0;    for(int i=0;i<n;i++){        int j=sa[rank[i]-1];        if(h>0)h--;        while(i+h<n&&j+h<n&&s[i+h]==s[j+h])h++;        lcp[rank[i]-1]=h;    }}char buf[2][maxn];int Stack[maxn];int num[maxn];int main(){    int len;    while(scanf("%d",&len)&&len){        scanf("%s%s",buf[0],buf[1]);        int len1=strlen(buf[0]);        strcat(buf[0],"@");        strcat(buf[0],buf[1]);        getSa(buf[0]);getLcp(buf[0]);//        for(int i=0;i<=n;i++){//            printf("%s\n",buf[0]+sa[i]);//        }        LL tot=0,top=0,cnt=0;        LL ans=0;        for(int i=1;i<=n;i++){            if(lcp[i-1]<len)top=tot=0;//根据lcp进行分组操作            else{//在同一组的                cnt=0;                if(sa[i-1]<len1)cnt++,tot+=lcp[i-1]-len+1;                while(top>0&&lcp[i-1]<=Stack[top-1]){//保证栈的单调性                    top--;                    tot-=num[top]*(Stack[top]-lcp[i-1]);//去掉多加的                    cnt+=num[top];//累计个数                }                num[top]=cnt;                Stack[top++]=lcp[i-1];                if(sa[i]>len1)ans+=tot;            }        }        tot=top=0;        for(int i=1;i<=n;i++){            if(lcp[i-1]<len)top=tot=0;            else{                cnt=0;                if(sa[i-1]>len1)cnt++,tot+=lcp[i-1]-len+1;                while(top>0&&lcp[i-1]<=Stack[top-1]){                    top--;                    tot-=num[top]*(Stack[top]-lcp[i-1]);                    cnt+=num[top];                }                num[top]=cnt;                Stack[top++]=lcp[i-1];                if(sa[i]<len1)ans+=tot;            }        }        printf("%lld\n",ans);    }    return 0;}
0 0
原创粉丝点击