3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 1890 Solved: 877
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
一看这个题,感觉超级水,,就直接用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); } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。