您的位置:首页 > 其它

bzoj 3172 TJOI2013单词

2018-03-28 21:27 218 查看
http://www.elijahqi.win/archives/613

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

复习一下昨天的二分查找,但是复杂度感觉是玄学,还不如暴力跑得快

就是找到最长的满足区间内height都大于等于Len 求这个最大长度,分别在左右二分就可以了

nlogn 2628 ms

#include<cstdio>
#include<cstring>
#define N 1100000
#define N1 220
int n,n1,a
,m,k,rank[N<<1],rank1
,sa
,count
,tmp
,height
,Log
,fmin
[20];
char str1
;
struct node{
int st,len;
}data[N1];
inline int min(int x,int y){return x<y?x:y;}
inline int lcp(int x,int y){
x++;int t=Log[y-x+1];
return min(fmin[x][t],fmin[y-(1<<t)+1][t]);
}
void check(int st,int len){
int l1,r1;
if (height[st]<len) l1=st;else{
int l=1,r=st-1;
while (l<=r){
int mid=(l+r)>>1;
if(lcp(mid,st)>=len) r=mid-1;else l=mid+1;
}
l1=l;
}
if (height[st+1]<len) r1=st;else{
int l=st+1,r=n;
while (l<=r){
int mid=(l+r)>>1;
if (lcp(st,mid)>=len) l=mid+1;else r=mid-1;
}
r1=r;
}
printf("%d\n",r1-l1+1);
}
int main(){
freopen("bzoj3172.in","r",stdin);
scanf("%d",&n1);n=1;m=30;
for (int i=1;i<=n1;++i) {
scanf("%s",str1);int nn=strlen(str1);data[i].len=nn;data[i].st=n;
for (int j=0;j<nn;++j) a[n+j]=str1[j]-'a'+1;n+=nn;a[n++]=m++;
}n-=1;
//for (int i=1;i<=n;++i) printf("%d ",a[i]);
//for (int i=1;i<=n1;++i) printf("%d %d\n",data[i].st,data[i].len);
for (int i=1;i<=n;++i) count[a[i]]=1;
for (int i=1;i<=255;++i) count[i]+=count[i-1];
for (int i=1;i<=n;++i) rank[i]=count[a[i]];
k=0;
for (int p=1;k!=n;p<<=1,m=k){
for (int i=1;i<=m;++i) count[i]=0;
for (int i=1;i<=n;++i) count[rank[i+p]]++;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) tmp[count[rank[i+p]]--]=i;
for (int i=1;i<=m;++i) count[i]=0;
for (int i=1;i<=n;++i) count[rank[i]]++;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) sa[count[rank[tmp[i]]]--]=tmp[i];
memcpy(rank1,rank,sizeof(rank)>>1);
rank[sa[1]]=k=1;
for (int i=2;i<=n;++i){
if (rank1[sa[i]]!=rank1[sa[i-1]]||rank1[sa[i-1]+p]!=rank1[sa[i]+p]) ++k;
rank[sa[i]]=k;
}
}
//  for (int i=1;i<=n;++i) printf("%d ",rank[i]);
k=0;
for (int i=1;i<=n;++i){
if (rank[i]==1) continue;
k=k==0?0:k-1;
while (a[i+k]==a[sa[rank[i]-1]+k]) ++k;
height[rank[i]]=k;
}
//for (int i=1;i<=n;++i) printf("%d ",height[i]);
Log[0]=-1;
for (int i=1;i<=n;++i) Log[i]=Log[i>>1]+1;
for (int i=1;i<=n;++i) fmin[i][0]=height[i];
for (int j=1;j<=Log
;++j){
for (int i=1;i<=n-(1<<j)+1;++i){
fmin[i][j]=min(fmin[i][j-1],fmin[i+(1<<(j-1))][j-1]);
}
}
for (int i=1;i<=n1;++i)
check(rank[data[i].st],data[i].len);
return 0;
}


暴力

1384 ms

#include<cstdio>
#include<cstring>
#define N 1100000
#define N1 220
int n,n1,a
,m,k,rank[N<<1],rank1
,sa
,count
,tmp
,height
;
char str1
;
struct node{
int st,len;
}data[N1];
int main(){
freopen("bzoj3172.in","r",stdin);
scanf("%d",&n1);n=1;m=30;
for (int i=1;i<=n1;++i) {
scanf("%s",str1);int nn=strlen(str1);data[i].len=nn;data[i].st=n;
for (int j=0;j<nn;++j) a[n+j]=str1[j]-'a'+1;n+=nn;a[n++]=m++;
}n-=1;
//for (int i=1;i<=n;++i) printf("%d ",a[i]);
//for (int i=1;i<=n1;++i) printf("%d %d\n",data[i].st,data[i].len);
for (int i=1;i<=n;++i) count[a[i]]=1;
for (int i=1;i<=255;++i) count[i]+=count[i-1];
for (int i=1;i<=n;++i) rank[i]=count[a[i]];
k=0;
for (int p=1;k!=n;p<<=1,m=k){
for (int i=1;i<=m;++i) count[i]=0;
for (int i=1;i<=n;++i) count[rank[i+p]]++;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) tmp[count[rank[i+p]]--]=i;
for (int i=1;i<=m;++i) count[i]=0;
for (int i=1;i<=n;++i) count[rank[i]]++;
for (int i=1;i<=m;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) sa[count[rank[tmp[i]]]--]=tmp[i];
memcpy(rank1,rank,sizeof(rank)>>1);
rank[sa[1]]=k=1;
for (int i=2;i<=n;++i){
if (rank1[sa[i]]!=rank1[sa[i-1]]||rank1[sa[i-1]+p]!=rank1[sa[i]+p]) ++k;
rank[sa[i]]=k;
}
}
//  for (int i=1;i<=n;++i) printf("%d ",rank[i]);
k=0;
for (int i=1;i<=n;++i){
if (rank[i]==1) continue;
k=k==0?0:k-1;
while (a[i+k]==a[sa[rank[i]-1]+k]) ++k;
height[rank[i]]=k;
}
//for (int i=1;i<=n;++i) printf("%d ",height[i]);

for(int i=1;i<=n1;++i){
int x=rank[data[i].st];
int l=x,r=x+1;
while(height[l]>=data[i].len) --l;
while(height[r]>=data[i].len) ++r;--r;
printf("%d\n",r-l+1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: