7
21
2015
0

BZOJ 3172 单词

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

 

将每一个单词读入,每一个单词中间用一个没有出现并小于前面字符的字符。之后用后缀数组算出公共前缀的height数组。

对于每个单词,向前后搜索,若公共前缀大于单词长度,说明出现过一次;

用来分隔的字符需要是最小的,我开始用最大的套模版,结果死循环了。。。。ORZ。会出现sa【0】==0的情况,貌似会挂。

 

代码:

/**************************************************************
    Problem: 3172
    User: 1115825064
    Language: C++
    Result: Accepted
    Time:1308 ms
    Memory:33496 kb
****************************************************************/
 
#include<iostream>
#include<cstdio> 
#include<cstring>
 
using namespace std;
 
const int N=1002001;
 
int r[N],rank[N],wa[N],wb[N],ws1[N],wv[N],h[N],sa[N];
 
int p[210],l[210],n;
 
bool cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
 
void da(int *r,int *sa,int n,int m)
{
    int *x=wa,*y=wb,*t;
    for(int i=0;i<m;++i) ws1[i]=0;
    for(int i=0;i<n;++i) ws1[x[i]=r[i]]++;
    for(int i=1;i<m;++i) ws1[i]+=ws1[i-1];
    for(int i=n-1;i>=0;i--) sa[--ws1[x[i]]]=i;
    for(int p1=1,j=1;p1<n;j*=2,m=p1)
    {
        p1=0;
        for(int i=n-j;i<n;i++) y[p1++]=i;
        for(int i=0;i<n;i++) if(sa[i]>=j) y[p1++]=sa[i]-j;
        for(int i=0;i<n;i++) wv[i]=x[y[i]];
        for(int i=0;i<m;++i) ws1[i]=0;
        for(int i=0;i<n;++i) ws1[wv[i]]++;
        for(int i=1;i<m;++i) ws1[i]+=ws1[i-1];
        for(int i=n-1;i>=0;--i) sa[--ws1[wv[i]]]=y[i];
        t=x,x=y,y=t,p1=1,x[sa[0]]=0;
        for(int i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p1-1:p1++;
             
         
    }
}
void height(int *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1;i<n;++i) rank[sa[i]]=i;
    for(i=0;i<n;h[rank[i++]]=k)
        for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];++k);
}
 
int main()
{
    scanf("%d",&n);
    int tot=0;
    for(int a,i=1;i<=n;++i)
    {
        char s[N];
        scanf("%s",s);
        a=strlen(s);
        p[i]=tot;
        for(int j1=0;j1<a;++j1)
            r[j1+tot]=s[j1]-'a'+2;
        l[i]=a;
        tot+=a;
        r[tot++]=1;
         
    }
     
    da(r,sa,tot,30);
     
    height(r,sa,tot);
     
    for(int i=1;i<=n;++i)
    {
        int t=rank[p[i]],j,left,right;
        for(j=t;j&&h[j]>=l[i];j--);
        left=j;
        for(j=t+1;j<tot&&h[j]>=l[i];j++);
        right=j;
        printf("%d\n",right-left);
    } 
}
Category: 未分类 | Tags: | Read Count: 406

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com