1. 程式人生 > >[bzoj3172] [Tjoi2013]單詞

[bzoj3172] [Tjoi2013]單詞

Description

某人讀論文,一篇論文是由許多單片語成。但他發現一個單詞會在論文中出現很多次,現在想知道每個單詞分別在論文中出現多少次。

Input

第一個一個整數N,表示有多少個單詞,接下來N行每行一個單詞。每個單詞由小寫字母組成,N<=200,單詞長度不超過10^6

Output

輸出N個整數,第i行的數字表示第i個單詞在文章中出現了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

Solution

字尾陣列,求出\(height\)之後怎麼暴力怎麼寫。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 1.1e6+10;

int st[maxn],len[maxn];
char tmp[maxn];
int N,cnt;

struct Suffix_Array {
    char s[maxn];
    int sa[maxn],Sp1[maxn],Sp2[maxn],sum[maxn],height[maxn],rk[maxn],m,n;
    void build() {
        int *x=Sp1,*y=Sp2;
        n=strlen(s+1),m=130;
        for(int i=1;i<=m;i++) sum[i]=0;
        for(int i=1;i<=n;i++) sum[x[i]=s[i]]++;
        for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
        for(int i=n;i;i--) sa[sum[x[i]]--]=i;

        for(int k=1,p=0,tot=0;p<n;k<<=1,tot=0) {
            for(int i=n-k+1;i<=n;i++) y[++tot]=i;
            for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
            
            for(int i=1;i<=m;i++) sum[i]=0;
            for(int i=1;i<=n;i++) sum[x[y[i]]]++;
            for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
            for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
            
            swap(x,y);x[sa[1]]=p=1;
            for(int i=2;i<=n;i++)
                if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
                else x[sa[i]]=p;
            m=p;
        }
    }

    void get_height() {
        for(int i=1;i<=n;i++) rk[sa[i]]=i;
        for(int i=1,p=1;i<=n;i++) {
            if(p) p--;
            while(s[i+p]==s[sa[rk[i]-1]+p]) p++;
            height[rk[i]]=p;
        }
    }

    void solve() {
        for(int i=1;i<=N;i++) {
            int ans=0;
            for(int j=rk[st[i]];j;j--)
                if(height[j]>=len[i]) ans++;
                else break;
            for(int j=rk[st[i]]+1;j<=n;j++)
                if(height[j]>=len[i]) ans++;
                else break;
            write(ans+1);
        }
    }
}SA;

int main() {
    read(N);
    for(int i=1;i<=N;i++) {
        scanf("%s",tmp+1);
        len[i]=strlen(tmp+1);st[i]=cnt+1;
        for(int j=1;j<=len[i];j++) SA.s[++cnt]=tmp[j];
        SA.s[++cnt]='$';
    }
    //cout << SA.s+1 << endl;
    SA.build();SA.get_height();
    SA.solve();
    return 0;
}