首页 > 代码库 > 【uva11855-求长度为1到n的相同子串出现的次数】sam
【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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。