zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
    

      

  • 相关阅读:
    LeetCode Path Sum II
    LeetCode Longest Palindromic Substring
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Binary Tree Maximum Path Sum
    LeetCode Find Peak Element
    LeetCode Maximum Product Subarray
    LeetCode Intersection of Two Linked Lists
    一天一个设计模式(1)——工厂模式
    PHP迭代器 Iterator
  • 原文地址:https://www.cnblogs.com/qt666/p/7106994.html
Copyright © 2011-2022 走看看