bzoj 3172: [Tjoi2013]单词

Description

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

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

HINT 

Source

思维越来越僵化。。。又是一道后缀数组傻逼题。。。

把所有的串拼在一起,中间用"#"隔开,然后记录每个串开始的位置st[i]和长度le[i]。

因为n很小可以每个串暴力;如果该串在别的串出现,那么以st[i]开头的后缀与别的后缀的lcp长度为le[i];

因为排名越靠近height越大,所以从rnk[st[i]]往左右两边扫,直到height小于le[i],则分组中的lcp长度为le[i],是所有的出现情况。

(upd:我发现我真的是头猪,while暴跳的话复杂度可能是平方的。。。正确的做法是要左右两边二分答案然后check LCP)

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=3000050;
int gi(){
  int x=0,flag=1;
  char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x*flag;
}
int sa[N],y[N],rnk[N],height[N],len,rk,le[N],st[N],n;
char ch[N],a[N];
struct data{
  int x1,x2,id;
}x[N];
bool cmp(const data &a,const data &b){
  if(a.x1==b.x1) return a.x2<b.x2;
  else return a.x1<b.x1;
}
void work2(){
  int rk=1;y[x[1].id]=1;
  for(int i=2;i<=len;i++){
    if(x[i].x1!=x[i-1].x1||x[i].x2!=x[i-1].x2) rk++;
    y[x[i].id]=rk;
  }
}
void work(){
  sort(x+1,x+1+len,cmp);work2();
  for(int i=1;i<=len;i<<=1){
    for(int j=1;j+i<=len;j++) x[j].id=j,x[j].x1=y[j],x[j].x2=y[j+i];
    for(int j=len-i+1;j<=len;j++) x[j].id=j,x[j].x1=y[j],x[j].x2=0;
    sort(x+1,x+1+len,cmp);work2();
    if(rk==len) break;
  }
}
void get_height(){
  int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
  for(int i=1;i<=len;i++){
    if(kk) kk--;
    int j=sa[rnk[i]-1];
    while(a[i+kk]==a[j+kk]) kk++;
    height[rnk[i]]=kk;
  }
}
void work3(int i){
  ll ret=1;int l=rnk[st[i]],r=rnk[st[i]]+1;
  while(height[l]>=le[i]) ret++,l--;
  while(height[r]>=le[i]) ret++,r++;
  printf("%lld\n",ret);
}
int main(){
  n=gi();
  for(int i=1;i<=n;i++){
    scanf("%s",ch+1);le[i]=strlen(ch+1);st[i]=len+1;
    for(int j=1;j<=le[i];j++) a[len+j]=ch[j];
    len+=le[i]+1;a[len]='#';
  }
  for(int i=1;i<=len;i++) x[i].id=i,x[i].x1=x[i].x2=a[i]-'a'+1;
  work();for(int i=1;i<=len;i++) sa[y[i]]=i;
  get_height();
  for(int i=1;i<=n;i++) work3(i);
  return 0;
}

  

posted @ 2017-07-02 20:04  qt666  阅读(142)  评论(0编辑  收藏  举报