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[N],m,k,rank[N<<1],rank1[N],sa[N],count[N],tmp[N],height[N],Log[N],fmin[N][20];
char str1[N];
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[n];++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[N],m,k,rank[N<<1],rank1[N],sa[N],count[N],tmp[N],height[N];
char str1[N];
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;
}