HDU 4436 後綴數組

點擊打開鏈接

題意:給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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章