3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1890 Solved: 877
[ Submit][ Status][ Discuss]
Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
a
aa
aaa
Sample Output
6
3
1
3
1
HINT
Source
一看这个题,感觉超级水,,就直接用ac自动机瞎搞了一下,然后跑了9000多ms过了,差点超时,吓哭了,然后百度人家都用后缀数组+RMQ或者ac自动机+fail树写的,fail树不懂是什么鬼,,就用后缀数组水了一下,把所有的串全部连到一个字符串,中间隔开,然后找每个出现的次数就行了,由后缀数组的性质可以知道,就是找height大于的长度向前最大向后最大的距离就是了,本想用RMQ和二分试试,感觉有点麻烦,就用暴力的试了试,样例对,提交过了,跑了1000多ms很不错,当感觉暴力是不是太慢了,就用RMQ+二分试了试,跑了2000多ms比暴力要慢,,但还是感觉可能数据弱的问题,第二种应该是比较好的写法,然后就去学了学fail树,实际上很简单就是把fail指针反向建成树,一直加到root,ac自动机数组版的反向加fail的值参照了一下HZW的,膜拜中学生啊~~~,跑了300多ms,果然碉堡了,,但是一直不习惯数组版的那种写法,有老老实实的写了一遍结构体的,建的fail树,感觉好理解多了,跑了400多ms,也不慢~~
ac代码
裸AC自动机搞
/**************************************************************
Problem: 3172
User: kxh1995
Language: C++
Result: Accepted
Time:9228 ms
Memory:314756 kb
****************************************************************/
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
const int maxnode=1000000+10;
const int sg_size=27;
char str[200000010],key[1000010];
int pos[220];
struct Trie
{
int ch[maxnode][sg_size];
int val[maxnode];
int f[maxnode];
int num[maxnode];
int sz;
void init()
{
sz=1;
memset(ch,0,sizeof(ch));
memset(val,0,sizeof(val));
memset(f,0,sizeof(f));
memset(num,0,sizeof(num));
}
int idx(char c)
{
return c-'a';
}
int insert(char *s)
{
int u=0,i;
for(i=0;s[i];i++)
{
int c=idx(s[i]);
if(!ch[u][c])
ch[u][c]=sz++;;
u=ch[u][c];
}
val[u]++;
num[u]=0;
return u;
}
void build_ac()
{
queue<int>q;
int i;
for(i=0;i<sg_size;i++)
{
if(ch[0][i])
q.push(ch[0][i]);
}
int r,c,u,v;
while(!q.empty())
{
r=q.front();
q.pop();
for(c=0;c<sg_size;c++)
{
u=ch[r][c];
if(!u)
continue;
q.push(u);
v=f[r];
while(v&&ch[v][c]==0)
v=f[v];
f[u]=ch[v][c];
}
}
}
void find(char *s)
{
int j=0;
for(int i=0;s[i];i++)
{
int c=idx(s[i]);
while(j&&ch[j][c]==0)
j=f[j];
j=ch[j][c];
int temp=j;
while(temp)
{
num[temp]++;
temp=f[temp];
}
}
}
}ac;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i;
ac.init();
int len;
for(i=1;i<=n;i++)
{
scanf("%s",key);
pos[i]=ac.insert(key);
strcat(str,key);
len=strlen(str);
str[len]='z'+1;
str[len+1]='\0';
}
ac.build_ac();
ac.find(str);
for(i=1;i<=n;i++)
{
printf("%d\n",ac.num[pos[i]]);
}
}
}
后缀数组暴力版
/**************************************************************
Problem: 3172
User: kxh1995
Language: C++
Result: Accepted
Time:1528 ms
Memory:25712 kb
****************************************************************/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define N 1001000
using namespace std;
char str[N];
int sa[N],Rank[N],rank2[N],height[N],c[N],*x,*y,s[N],k;
void cmp(int n,int sz)
{
int i;
memset(c,0,sizeof(c));
for(i=0;i<n;i++)
c[x[y[i]]]++;
for(i=1;i<sz;i++)
c[i]+=c[i-1];
for(i=n-1;i>=0;i--)
sa[--c[x[y[i]]]]=y[i];
}
void build_sa(char *s,int n,int sz)
{
x=Rank,y=rank2;
int i,j;
for(i=0;i<n;i++)
x[i]=s[i],y[i]=i;
cmp(n,sz);
int len;
for(len=1;len<n;len<<=1)
{
int yid=0;
for(i=n-len;i<n;i++)
{
y[yid++]=i;
}
for(i=0;i<n;i++)
if(sa[i]>=len)
y[yid++]=sa[i]-len;
cmp(n,sz);
swap(x,y);
x[sa[0]]=yid=0;
for(i=1;i<n;i++)
{
if(y[sa[i-1]]==y[sa[i]]&&sa[i-1]+len<n&&sa[i]+len<n&&y[sa[i-1]+len]==y[sa[i]+len])
x[sa[i]]=yid;
else
x[sa[i]]=++yid;
}
sz=yid+1;
if(sz>=n)
break;
}
for(i=0;i<n;i++)
Rank[i]=x[i];
}
void getHeight(char *s,int n)
{
int k=0;
for(int i=0;i<n;i++)
{
if(Rank[i]==0)
continue;
k=max(0,k-1);
int j=sa[Rank[i]-1];
while(s[i+k]==s[j+k])
k++;
height[Rank[i]]=k;
}
}
int l[220],r[220];
int main()
{
int kk;
while(scanf("%d",&kk)!=EOF)
{
int n=0;
int i,j;
for(i=1;i<=kk;i++)
{
scanf("%s",str+n);
l[i]=n;
n=strlen(str);
r[i]=n-l[i];
str[n++]='z'+1;
}
str[n]=0;
build_sa(str,n+1,128);
getHeight(str,n);
for(i=1;i<=kk;i++)
{
int t=Rank[l[i]],len=r[i],rr,ll;
for(j=t;j&&height[j]>=len;j--);
ll=j;
for(j=t+1;j<n&&height[j]>=len;j++);
rr=j;
printf("%d\n",rr-ll);
}
}
}
后缀数组+RMQ+二分版
/**************************************************************
Problem: 3172
User: kxh1995
Language: C++
Result: Accepted
Time:2756 ms
Memory:107824 kb
****************************************************************/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define N 1001000
using namespace std;
char str[N];
int sa[N],Rank[N],rank2[N],height[N],c[N],*x,*y,s[N],k;
void cmp(int n,int sz)
{
int i;
memset(c,0,sizeof(c));
for(i=0;i<n;i++)
c[x[y[i]]]++;
for(i=1;i<sz;i++)
c[i]+=c[i-1];
for(i=n-1;i>=0;i--)
sa[--c[x[y[i]]]]=y[i];
}
void build_sa(char *s,int n,int sz)
{
x=Rank,y=rank2;
int i,j;
for(i=0;i<n;i++)
x[i]=s[i],y[i]=i;
cmp(n,sz);
int len;
for(len=1;len<n;len<<=1)
{
int yid=0;
for(i=n-len;i<n;i++)
{
y[yid++]=i;
}
for(i=0;i<n;i++)
if(sa[i]>=len)
y[yid++]=sa[i]-len;
cmp(n,sz);
swap(x,y);
x[sa[0]]=yid=0;
for(i=1;i<n;i++)
{
if(y[sa[i-1]]==y[sa[i]]&&sa[i-1]+len<n&&sa[i]+len<n&&y[sa[i-1]+len]==y[sa[i]+len])
x[sa[i]]=yid;
else
x[sa[i]]=++yid;
}
sz=yid+1;
if(sz>=n)
break;
}
for(i=0;i<n;i++)
Rank[i]=x[i];
}
void getHeight(char *s,int n)
{
int k=0;
for(int i=0;i<n;i++)
{
if(Rank[i]==0)
continue;
k=max(0,k-1);
int j=sa[Rank[i]-1];
while(s[i+k]==s[j+k])
k++;
height[Rank[i]]=k;
}
}
int minv[N][20],lg[N];
void init_lg()
{
int i;
lg[1]=0;
for(i=2;i<N;i++)
{
lg[i]=lg[i>>1]+1;
}
}
void init_RMQ(int n)
{
int i,j,k;
for(i=1;i<=n;i++)
{
minv[i][0]=height[i];
}
for(j=1;j<=lg[n];j++)
{
for(k=0;k+(1<<j)-1<=n;k++)
{
minv[k][j]=min(minv[k][j-1],minv[k+(1<<(j-1))][j-1]);
}
}
}
int lcp(int l,int r)
{
if(l>r)
swap(l,r);
//l++;
int k=lg[r-l+1];
return min(minv[l][k],minv[r-(1<<k)+1][k]);
}
int l[220],r[220];
int main()
{
int kk;
while(scanf("%d",&kk)!=EOF)
{
int n=0;
int i,j;
for(i=1;i<=kk;i++)
{
scanf("%s",str+n);
l[i]=n;
n=strlen(str);
r[i]=n-l[i];
str[n++]='z'+1;
}
str[n]=0;
build_sa(str,n+1,128);
getHeight(str,n);
init_lg();
init_RMQ(n);
for(i=1;i<=kk;i++)
{
int t=Rank[l[i]],len=r[i],rr,ll;
int ml=0,mr=t;
int ans=0,tot=1;
while(ml<=mr)
{
int mid=(ml+mr)>>1;
if(lcp(mid,t)>=len)
{
ans=mid;
mr=mid-1;
}
else
ml=mid+1;
}
//ll=ans;
//printf("*******%d\n",ll);
if(ans)
ans=t-ans+1;
tot+=ans;
ml=t+1,mr=n-1;
ans=0;
while(ml<=mr)
{
int mid=(ml+mr)>>1;
if(lcp(t+1,mid)>=len)
{
ans=mid;
ml=mid+1;
}
else
mr=mid-1;
}
if(ans)
ans=ans-t;
tot+=ans;
// rr=ans;
// printf("********%d\n",rr);
printf("%d\n",tot);
}
}
}
AC自动机反向加fail的值数组版
/**************************************************************
Problem: 3172
User: kxh1995
Language: C++
Result: Accepted
Time:324 ms
Memory:115532 kb
****************************************************************/
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
const int maxnode=1000000+10;
const int sg_size=26;
char key[1000010];
int pos[220];
struct Trie
{
int ch[maxnode][sg_size];
int f[maxnode];
int sum[maxnode];
int q[maxnode];
int sz;
void init()
{
sz=1;
// memset(ch,0,sizeof(ch));
for(int i=0;i<26;i++)
ch[0][i]=1;
memset(f,0,sizeof(f));
memset(sum,0,sizeof(sum));
}
int idx(char c)
{
return c-'a';
}
int insert(char *s)
{
int u=1,i;
for(i=0;s[i];i++)
{
int c=idx(s[i]);
if(!ch[u][c])
ch[u][c]=++sz;
u=ch[u][c];
sum[u]++;
}
return u;
}
void build_ac()
{
int head=0;
int tail=1;
q[0]=1;
while(head!=tail)
{
int r=q[head];
head++;
for(int c=0;c<sg_size;c++)
{
int u=ch[r][c];
if(!u)
continue;
q[tail++]=u;
int v=f[r];
while(v&&ch[v][c]==0)
v=f[v];
f[u]=ch[v][c];
}
}
for(int i=tail-1;i>=0;i--)
{
sum[f[q[i]]]+=sum[q[i]];
}
}
}ac;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i;
ac.init();
int len;
for(i=1;i<=n;i++)
{
scanf("%s",key);
pos[i]=ac.insert(key);
}
ac.build_ac();
for(i=1;i<=n;i++)
{
printf("%d\n",ac.sum[pos[i]]);
}
}
}
ac自动机+fail树
/**************************************************************
Problem: 3172
User: kxh1995
Language: C++
Result: Accepted
Time:452 ms
Memory:229136 kb
****************************************************************/
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
char key[1000001];
int head,tail;
int sz=0;
struct node
{
node *fail;
node *next[26];
int cnt,num;
node()
{
fail=NULL;
cnt=0;
for(int i=0;i<26;i++)
next[i]=NULL;
num=sz++;
}
}*q[26000500],*p1[220];
struct Edge
{
node *y;
Edge *next;
}*b[26000100];
node *root;
void add(node *x,node *y)
{
Edge *k=new Edge;
k->y=y;
k->next=b[x->num];
b[x->num]=k;
}
void insert(char *s,int key)
{
int temp,len,i;
node *p=root;
len=strlen(s);
for(i=0;i<len;i++)
{
temp=s[i]-'a';
if(p->next[temp]==NULL)
p->next[temp]=new node();
p=p->next[temp];
p->cnt++;
}
p1[key]=p;
}
void build_ac()
{
head=tail=0;
q[tail++]=root;
while(head!=tail)
{
node *p=q[head++];
node *temp=NULL;
for(int i=0;i<26;i++)
{
if(p->next[i]!=NULL)
{
if(p==root)
{
p->next[i]->fail=root;
add(root,p->next[i]);
}
else
{
temp=p->fail;
while(temp!=NULL)
{
if(temp->next[i]!=NULL)
{
p->next[i]->fail=temp->next[i];
add(temp->next[i],p->next[i]);
break;
}
temp=temp->fail;
}
if(temp==NULL)
{
p->next[i]->fail=root;
add(root,p->next[i]);
}
}
q[tail++]=p->next[i];
}
}
}
}
void dfs(node *fa)
{
Edge *p;
for(p=b[fa->num];p!=NULL;p=p->next)
{
dfs(p->y);
fa->cnt+=p->y->cnt;
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
head=tail=0;
sz=0;
root=new node();
int i;
for(i=1;i<=n;i++)
{
scanf("%s",key);
insert(key,i);
}
build_ac();
dfs(root);
for(i=1;i<=n;i++)
{
printf("%d\n",p1[i]->cnt);
}
}
}