HDU 4436 后缀数组

来源:互联网 发布:淘宝估值 编辑:程序博客网 时间:2024/05/17 22:42

点击打开链接

题意:给n个串,求所有的子串去重后相加对2012取余的值

思路:思路借鉴这篇博客,其中有一个求一段串可以形成的和有点类似与字符串hash的想法,用的很巧,要用后缀数组的话不同两个串的连接需要用一个其他的数字,然后正常计算sa和height,然后当遇到的第i个是加的那个数字或者是0都不计算,因为题目说前导不能为0,然后i+height[Rank[i]]要小于i所在的串的结束位置,然后计算的式子就是要加的结果,画一画样例就好理解了

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const ll INF=0x3f3f3f3f3f3f3f3fll;const int MAXN=200010;const int mod=2012;int sa[MAXN];int t1[MAXN],t2[MAXN],c[MAXN];int Rank[MAXN],height[MAXN];void construct_sa(int s[],int n,int m){    int i,j,p,*x=t1,*y=t2;    for(i=0;i<m;i++)c[i]=0;    for(i=0;i<n;i++)c[x[i]=s[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(j=1;j<=n;j<<=1){        p=0;        for(i=n-j;i<n;i++)y[p++]=i;        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;        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]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;        if(p>=n)break;        m=p;    }}void construct_lcp(int s[],int n){    int k=0;    for(int i=0;i<=n;i++) Rank[sa[i]]=i;    for(int i=0;i<n;i++){        if(k)k--;        int j=sa[Rank[i]-1];        while(s[i+k]==s[j+k])k++;        height[Rank[i]]=k;    }}int s[MAXN],id[MAXN],sum[MAXN],T[MAXN],V[MAXN],base[MAXN],arrive[MAXN];char str[MAXN];int calc_sum(int l,int r){    int ans=T[r+1]-T[l];    ans%=mod;ans-=V[l]*base[r-l+1];    ans=(ans+mod)%mod;    if(ans<0) ans+=mod;    return ans;}int main(){    base[1]=10;for(int i=2;i<MAXN;i++) base[i]=(base[i-1]+1)*10%mod;    int n;    while(scanf("%d",&n)!=-1){        int k=0,val=0;        for(int i=1;i<=n;i++){            scanf("%s",str);            int len=strlen(str);            for(int j=0;j<len;j++){                s[k]=str[j]-'0'+1;                val=(val*10+s[k]-1)%mod;                V[k+1]=val;                T[k+1]=(T[k]+val)%mod;                id[k]=i;k++;            }            s[k]=11;            val=(val*10+10)%mod;            V[k+1]=val;            T[k+1]=(T[k]+val)%mod;            id[k]=i;k++;arrive[i]=k-2;        }        s[k]=0;        construct_sa(s,k+1,128);        construct_lcp(s,k);        int ans=0;        for(int i=0;i<k;i++){            if(s[i]%10!=1){                if(i+height[Rank[i]]<=arrive[id[i]]){//小于这个界限才会有不重复的串                    ans+=calc_sum(i,arrive[id[i]])-calc_sum(i,i+height[Rank[i]]-1);                    ans=(ans+mod)%mod;                    if(ans<0) ans+=mod;                }            }        }        printf("%d\n",ans);    }    return 0;}

0 0