bzoj3172: [Tjoi2013]单词
来源:互联网 发布:java生成二维数组 编辑:程序博客网 时间:2024/05/29 15:51
Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaaSample Output
6
3
1题解:
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
a
aa
aaa
3
1
先将所有字符串拼起来,然后求一遍后缀数组,找到第以i个串开头的后缀的位置,求出向左走保证height[x]>=len[i]的最小的x,以及向右走height[y]>=len[i]的最大的y,那么答案就是y-x+2;
向左扩展或向右扩展在扩展的过程中,min(height[x])肯定单调不增,所以可以二分答案,rmq预处理区间最小值,时间复杂度O(nlogn)
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn=1000000+210;char A[maxn];int sa[maxn],rk[maxn],tmp[maxn],c[maxn];int n;int minn[maxn][22];int sum[maxn];int len[maxn];int height[maxn];int lg[maxn];int tot=0;char B[maxn];inline void get_sa(){ int *rnk=rk,*tp=tmp; n=strlen(A+1); int m=300; for(int i=1;i<=n;i++) tp[i]=A[i],rnk[i]=A[i]; for(int i=0;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[tp[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[tp[i]]--]=i; for(int j=1;j<=n;j<<=1){ int p=0; for(int i=n-j+1;i<=n;i++) tp[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>j) tp[++p]=sa[i]-j; for(int i=0;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[rnk[tp[i]]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[rnk[tp[i]]]--]=tp[i]; swap(rnk,tp); rnk[sa[1]]=1; p=1; for(int i=2;i<=n;i++){ int O1=sa[i]+j>n?-1:tp[sa[i]+j]; int O2=sa[i-1]+j>n?-1:tp[sa[i-1]+j]; rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&O1==O2)?p:++p; } m=p; if(m>=n) break; }}inline void get_height(){ for(int i=1;i<=tot;i++) rk[sa[i]]=i; int h=0; for(int i=1;i<=tot;i++){ --h=h<0?0:h; int u=sa[rk[i]-1]; while(A[u+h]==A[i+h]) h++; height[rk[i]]=h; }}inline void rmq_pre(){ for(int i=1;i<=tot;i++){ int u=1,cnt=0; while(u<=i) u<<=1,cnt++; lg[i]=cnt-1; } for(int i=1;i<=tot;i++) minn[i][0]=height[i]; for(int j=1;j<=30;j++) for(int i=1;i<=tot;i++){ if(i+(1<<j)-1>tot) break; minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]); }}inline int get_min(int l,int r){ if(l>r) return 0x3f3f3f3f; int u=lg[r-l+1]; return min(minn[l][u],minn[r-(1<<u)+1][u]);}inline int get_l(int x,int length){ int l=1,r=x; while(l+1<r){ int mid=(l+r)>>1; int u=get_min(mid+1,x); if(u>=length) r=mid; else l=mid; } if(get_min(l+1,x)>=length) return l; return r;}inline int get_r(int x,int length){ int l=x,r=tot; while(l+1<r){ int mid=(l+r)>>1; int u=get_min(x+1,mid); if(u>=length) l=mid; else r=mid; } if(get_min(x+1,r)>=length) return r; return l;}inline void work(int i){ int t=rk[sum[i-1]+1]; int l=get_l(t,len[i]),r=get_r(t,len[i]); //printf("%d %d\n",l,r); printf("%d\n",r-l+1);}int main(){ //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",B+1); len[i]=strlen(B+1); for(int j=1;j<=len[i];j++) A[++tot]=B[j]; if(i!=n) A[++tot]='z'+1; sum[i]=sum[i-1]+len[i]+(i!=n); } get_sa(); get_height(); rmq_pre(); for(int i=1;i<=n;i++) work(i); //for(int i=1;i<=tot;i++) // printf("%d ",sa[i]);return 0;}
阅读全文
0 0
- bzoj3172: [Tjoi2013]单词
- 【AhoCorasickAutoMata】bzoj3172[Tjoi2013]单词
- 【TJOI2013】【BZOJ3172】单词
- [BZOJ3172][Tjoi2013]单词
- [BZOJ3172][Tjoi2013]单词
- bzoj3172【TJOI2013】单词
- BZOJ3172 TJOI2013 单词
- [bzoj3172][TJOI2013]单词
- bzoj3172: [Tjoi2013]单词
- BZOJ3172: [Tjoi2013]单词
- bzoj3172: [Tjoi2013]单词
- bzoj3172 [Tjoi2013]单词
- [bzoj3172][Tjoi2013]单词
- bzoj3172: [Tjoi2013]单词
- [BZOJ3172]TJOI2013单词|AC自动机
- 【bzoj3172】【TJOI2013】【单词】【AC自动机】
- BZOJ3172——[Tjoi2013]单词
- [BZOJ3172] [TJOI2013] 单词 - AC自动机
- Samba案例分析
- Missing artifact jdk.tools:jdk.tools:jar:1.8
- 多线程 Callable Runnable 与Future
- 基于 SquashFS 构建 Linux 可读写文件系统
- 浅析 Linux 初始化 init 系统 systemd
- bzoj3172: [Tjoi2013]单词
- bzoj1026: [SCOI2009]windy数
- C的小项目:注释转换
- 为什么spinlock需要提升IRQL到Dispatch Level?
- 三十分钟理解:双调排序Bitonic Sort,适合并行计算的排序算法
- gcc链接参数
- 通过程序设计几何图形(Shape)、矩形(Rectangle)、圆形(Circle)、正方形(Square)几种类型, 能够利用接口和多态性计算几何图形的面积和周长并显示。
- 2、按以下要求编写程序 (1) 编写Animal接口,接口中声明run() 方法 (2) 定义Bird类和Fish类实现Animal接口 (3) 编写Bird类和Fish类的测试程序,并调用其
- 1、利用String类或StringBuffer类的方法,对输入的Email地址进行有效性验证。提示:1)Email地址中应包含“@”和“.”符号;2)“@”