zoukankan      html  css  js  c++  java
  • BZOJ 3172([Tjoi2013]单词-后缀数组第一题+RMQ)

    3172: [Tjoi2013]单词

    Time Limit: 10 Sec   Memory Limit: 512 MB
    Submit: 268   Solved: 145
    [ Submit][ Status]

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    a
    aa
    aaa

    Sample Output

    6
    3
    1

    上一次写RMQ是什么时候?(喂,离题了)

    好吧……

    第一题后缀数组

    不想写下去了……(快哭了TNT)

    这题在BZOJ上内存很容易开过(5人组-》TLE/CE/MLE/RE/AC)

    大家要是这题RE把数组开小点。别忘了[RMQ*20]数组+数组之和 //省空间

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    #include<cmath>
    #include<cctype>
    using namespace std;
    #define For(i,n) for(int i=1;i<=n;i++)
    #define Rep(i,n) for(int i=0;i<n;i++)
    #define Fork(i,k,n) for(int i=k;i<=n;i++)
    #define ForD(i,n) for(int i=n;i;i--)
    #define Forp(x) for(int p=pre[x];p;p=next[p])
    #define RepD(i,n) for(int i=n;i>=0;i--)
    #define MEM(a) memset(a,0,sizeof(a))
    #define MEMI(a) memset(a,127,sizeof(a))
    #define MEMi(a) memset(a,128,sizeof(a))
    #define INF (2139062143)
    #define F (1000000009)
    #define MAXN (300+10)
    #define MAXL (1000200+10)
    #define eps (1e-9)
    typedef long long ll;
    char s[MAXL];
    int n,pre[MAXN],tai[MAXN];
    int w[MAXL],sa[MAXL],wa[MAXL*2]={0},wb[MAXL*2]={0};
    // x-->上一行 y->下一行sa右值   wv-->y的左值  sa-->上次排名(求) 
    bool cmp(int *a,int x,int y,int l){return (a[x]==a[y]&&a[x+l]==a[y+l]);}
    void suffix_array(int n,int m)
    {
       int *x=wa,*y=wb;
       For(i,m) w[i]=0;
       For(i,n) w[x[i]=s[i]]++;
       Fork(i,2,m) w[i]+=w[i-1];
       ForD(i,n) sa[w[x[i]]--]=i;
       for(int j=1,p=0;p<n;j*=2,m=p)
       {
               
          p=0;
          Fork(i,n-j+1,n) y[++p]=i;
          For(i,n) if (j<sa[i]) y[++p]=sa[i]-j;
          
          For(i,m) w[i]=0;
          For(i,n) w[x[i]]++;
          For(i,m) w[i]+=w[i-1];
          
          
          ForD(i,n) sa[w[x[ y[i] ]]--]=y[i];
          //y is release
          
          p=y[sa[1]]=1;
          Fork(i,2,n)
             y[sa[i]]=(p+=(!cmp(x,sa[i-1],sa[i],j)));
    
          int *t=x;x=y;y=t;
       }
    }
    int height[MAXL],rank[MAXL]; //height[i] 表示 sa[i]与sa[i-1]的最长公共前缀 
    void make_height(char *s,int n)
    {
       For(i,n) rank[sa[i]]=i;
       For(i,n)
       {
          if (rank[i]==1) continue; //求height[rank[i]] 
          int j=max(0,height[rank[i-1]]-1),k=sa[rank[i]-1];
          while (s[i+j]==s[k+j]) j++;
          height[rank[i]]=j;
       }
    }
    int bin[MAXN]={0},f[MAXL][24]={0};
    int lcp(int l,int r)
    {
       int len=r-l+1,j=(int)log2(len);
       return min(f[l][j],f[r-bin[j]+1][j]);
    }
    int main()
    {
    // freopen("bzoj3172.in","r",stdin);
       scanf("%d",&n);pre[1]=1;
       For(i,n)
       {
          scanf("%s",s+pre[i]);
          tai[i]=strlen(s+pre[i]);
          s[pre[i]+tai[i]]='#';
          pre[i+1]=pre[i]+tai[i]+1;
       }
       s[pre[n+1]]=0;
       
       suffix_array(pre[n+1]-1,200);
       
       make_height(s,pre[n+1]-1);
       
       
       int logn=int(log2((double)pre[n+1]-1)+1);
       bin[0]=1;
       For(i,logn) bin[i]=bin[i-1]<<1;
       For(i,pre[n+1]-1) f[i][0]=height[i];
       
       For(j,logn)
          For(i,pre[n+1]-1-(1<<j)+1)
             f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
       
       For(i,n)
       {
          int tot=1;
          int j=rank[pre[i]]+1;
          {
             int l=2,r=j-1,ans=0;
             while (l<=r)
             {
                int m=l+r>>1;
                if (lcp(m,j-1)>=tai[i]) ans=m,r=m-1;
                else l=m+1;             
             }
             if (ans) ans=j-1-ans+1;
             tot+=ans;
          }
          {
             int l=j,r=pre[n+1]-1,ans=0;
             while (l<=r)
             {
                int m=l+r>>1;
                if (lcp(j,m)>=tai[i]) ans=m,l=m+1;
                else r=m-1;
             }
             if (ans) ans=ans-j+1;
             tot+=ans;
          }
          cout<<tot<<endl;
       }
    // while (1);
       return 0;
    }
    



  • 相关阅读:
    selenium
    python第三方模块的安装
    程序员学习网站
    python 数据较大 性能分析
    linux ~/ 和 /
    VMWare虚拟机 window文件传递
    vi命令
    os.system
    win10系统进入BIOS
    pyinstaller将python脚本生成exe
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3174485.html
Copyright © 2011-2022 走看看