zoukankan      html  css  js  c++  java
  • [bzoj3172] [Tjoi2013]单词

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    a
    aa
    aaa
    

    Sample Output

    6
    3
    1
    

    Solution

    后缀数组,求出(height)之后怎么暴力怎么写。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1.1e6+10;
    
    int st[maxn],len[maxn];
    char tmp[maxn];
    int N,cnt;
    
    struct Suffix_Array {
    	char s[maxn];
    	int sa[maxn],Sp1[maxn],Sp2[maxn],sum[maxn],height[maxn],rk[maxn],m,n;
    	void build() {
    		int *x=Sp1,*y=Sp2;
    		n=strlen(s+1),m=130;
    		for(int i=1;i<=m;i++) sum[i]=0;
    		for(int i=1;i<=n;i++) sum[x[i]=s[i]]++;
    		for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    		for(int i=n;i;i--) sa[sum[x[i]]--]=i;
    
    		for(int k=1,p=0,tot=0;p<n;k<<=1,tot=0) {
    			for(int i=n-k+1;i<=n;i++) y[++tot]=i;
    			for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
    			
    			for(int i=1;i<=m;i++) sum[i]=0;
    			for(int i=1;i<=n;i++) sum[x[y[i]]]++;
    			for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    			for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
    			
    			swap(x,y);x[sa[1]]=p=1;
    			for(int i=2;i<=n;i++)
    				if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
    				else x[sa[i]]=p;
    			m=p;
    		}
    	}
    
    	void get_height() {
    		for(int i=1;i<=n;i++) rk[sa[i]]=i;
    		for(int i=1,p=1;i<=n;i++) {
    			if(p) p--;
    			while(s[i+p]==s[sa[rk[i]-1]+p]) p++;
    			height[rk[i]]=p;
    		}
        }
    
    	void solve() {
    		for(int i=1;i<=N;i++) {
    			int ans=0;
    			for(int j=rk[st[i]];j;j--)
    				if(height[j]>=len[i]) ans++;
    				else break;
    			for(int j=rk[st[i]]+1;j<=n;j++)
    				if(height[j]>=len[i]) ans++;
    				else break;
    			write(ans+1);
    		}
    	}
    }SA;
    
    int main() {
    	read(N);
    	for(int i=1;i<=N;i++) {
    		scanf("%s",tmp+1);
    		len[i]=strlen(tmp+1);st[i]=cnt+1;
    		for(int j=1;j<=len[i];j++) SA.s[++cnt]=tmp[j];
    		SA.s[++cnt]='$';
    	}
    	//cout << SA.s+1 << endl;
    	SA.build();SA.get_height();
    	SA.solve();
    	return 0;
    }
    
  • 相关阅读:
    2015-05-27 用正则把oracle时间转化到mysql时间
    linux版idea14界面美观和windows,mac基本一致
    ubuntu 下自定义快捷键,,用着舒服
    ubuntu 方便好用的截图软件
    Integer 包装器类 大小比较
    win7、ubuntu双系统,遇到分区不可用问题,和卸载ubuntu后win7开不了机
    巧妙小思想
    读取16进制文件和校验图片格式的问题。 文件名后缀
    旧电脑变废为宝!
    Win10打开Autodesk软件时提示“管理员已阻止你运行此应用”
  • 原文地址:https://www.cnblogs.com/hbyer/p/10260421.html
Copyright © 2011-2022 走看看