• 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;
    }
    

      

  • 相关阅读:
    win10使用Scoop软件包管理器,支持版本切换
    使用ddns-go实现本地IP或公网IP动态域名解析
    使用Frp实现内网穿透
    Win10开发环境搭建
    Java使用Jabba进行版本管理
    Win10将用户目录Users迁移到其他盘
    【测试开发】十五、接口测试-接口定义-实现接口编辑功能
    【测试开发】十四、接口测试-接口定义功能-前后端-实现新增
    【测试开发】十三、接口测试-接口定义功能-前端-实现动态增删表单
    【测试开发】十二、接口测试-实现接口列表功能-递归查询子节点下的接口
  • 原文地址:https://www.cnblogs.com/qt666/p/7106994.html
Copyright © 2020-2023  润新知