uva11855-求长度为1到n的相同子串出现的次数sam
Posted Konjak谷弱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uva11855-求长度为1到n的相同子串出现的次数sam相关的知识,希望对你有一定的参考价值。
题意:求长度为1到n的相同子串出现的次数,输到小于2为止。
题解:
用sam做。
建机,算right集合,然后用r[i]更新长度为step[i]的子串出现次数,然后ans[i]=maxx(ans[i],ans[i+1])(长度更长的出现次数一定小于等于长度更短的。)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<queue> 6 using namespace std; 7 8 const int N=2*100010; 9 int sl,cl,tot,last,step[N],pre[N],son[N][30],in[N],r[N],c[N],ans[N]; 10 bool vis[N]; 11 char s[N]; 12 queue<int> Q; 13 14 int maxx(int x,int y){return x>y ? x:y;} 15 16 int add_node(int x) 17 { 18 step[++tot]=x; 19 return tot; 20 } 21 22 void clear() 23 { 24 memset(step,0,sizeof(step)); 25 memset(pre,0,sizeof(pre)); 26 memset(son,0,sizeof(son)); 27 memset(in,0,sizeof(in)); 28 memset(r,0,sizeof(r)); 29 tot=0;add_node(0);last=1; 30 } 31 32 void extend(int ch) 33 { 34 int p=last,np=add_node(step[p]+1); 35 while(p && !son[p][ch]) 36 { 37 son[p][ch]=np; 38 in[np]++; 39 p=pre[p]; 40 } 41 if(!p) pre[np]=1; 42 else 43 { 44 int q=son[p][ch]; 45 if(step[q]==step[p]+1) pre[np]=q; 46 else 47 { 48 int nq=add_node(step[p]+1); 49 for(int i=1;i<=26;i++) 50 if(son[q][i]) son[nq][i]=son[q][i],in[son[q][i]]++; 51 pre[nq]=pre[q]; 52 pre[np]=pre[q]=nq; 53 while(p && son[p][ch]==q) in[q]--,in[nq]++,son[p][ch]=nq,p=pre[p]; 54 } 55 } 56 last=np; 57 } 58 59 void get_tp() 60 { 61 while(!Q.empty()) Q.pop(); 62 memset(vis,0,sizeof(vis)); 63 Q.push(1);vis[1]=1;cl=0; 64 while(!Q.empty()) 65 { 66 int x=Q.front();c[++cl]=x;vis[x]=0;Q.pop(); 67 for(int i=1;i<=26;i++) 68 { 69 int y=son[x][i]; 70 if(!y) continue; 71 in[y]--; 72 if(!in[y] && !vis[y]) vis[y]=1,Q.push(y); 73 } 74 } 75 } 76 77 void get_right() 78 { 79 int x=1,ch; 80 for(int i=1;i<=sl;i++) 81 { 82 ch=s[i]-‘A‘+1; 83 x=son[x][ch]; 84 r[x]++; 85 } 86 for(int i=cl;i>=1;i--) r[pre[c[i]]]+=r[c[i]]; 87 } 88 89 void output(int x) 90 { 91 printf("x = %d pre = %d r = %d\n",x,pre[x],r[x]); 92 for(int i=1;i<=26;i++) 93 { 94 if(son[x][i]) printf("son %d = %d\n",i,son[x][i]); 95 } 96 printf("\n"); 97 } 98 99 int main() 100 { 101 freopen("a.in","r",stdin); 102 // freopen("a.out","w",stdout); 103 int cas=0; 104 while(1) 105 { 106 gets(s+1); 107 sl=strlen(s+1); 108 int l=0; 109 for(int i=1;i<=sl;i++) 110 if(s[i]>=‘A‘ && s[i]<=‘Z‘) s[++l]=s[i]; 111 sl=l; 112 if(sl==0) return 0; 113 114 clear(); 115 for(int i=1;i<=sl;i++) extend(s[i]-‘A‘+1); 116 get_tp(); 117 get_right(); 118 memset(ans,0,sizeof(ans)); 119 for(int i=1;i<=tot;i++) ans[step[i]]=maxx(ans[step[i]],r[i]); 120 121 for(int i=1;i<sl;i++) ans[i]=maxx(ans[i],ans[i+1]); 122 123 for(int i=1;i<=sl;i++) 124 { 125 if(ans[i]<2) break; 126 printf("%d\n",ans[i]); 127 } 128 printf("\n"); 129 } 130 return 0; 131 }
以上是关于uva11855-求长度为1到n的相同子串出现的次数sam的主要内容,如果未能解决你的问题,请参考以下文章
UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)