1. 程式人生 > >UVA-11107 Life Forms(求出現K次的子串,後綴數組+二分答案)

UVA-11107 Life Forms(求出現K次的子串,後綴數組+二分答案)

add src break 數組 nbsp line 技術 字符串長度 http

技術分享圖片

題解:

題意:

輸入n個DNA序列,你的任務是求出一個長度最大的字符串,使得它在超過一半的DNA序列中出現。如果有多解,按照字典序從小到大輸入所有解。

把n個DNA序列拼在一起,中間用沒有出現過的字符分割。然後求出height數組。

二分滿足要求的字符串長度L,然後判斷是否可行。

判斷可行:

分組方法,如果某一組(段)有超過n/2的DNA串(是對應的輸入的DNA串要有n/2個),則可行。

參考代碼:

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=100*2+10;
4 const int maxm=10000000*2; 5 int idx[maxm],n; 6 struct SuffixArray{ 7 int s[maxm]; 8 int sa[maxm],height[maxm],rank[maxm],n; 9 int t[maxm*2],t2[maxm*2]; 10 long long cnt[maxm]; 11 void clear(){n=0;} 12 void build_sa(int m) 13 { 14 int i,*x=t,*y=t2;
15 for(i=0;i<m;i++) cnt[i]=0; 16 for(i=0;i<n;i++) cnt[x[i]=s[i]]++; 17 for(i=1;i<m;i++) cnt[i]+=cnt[i-1]; 18 for(i=n-1;i>=0;i--) sa[--cnt[x[i]]]=i; 19 for(int k=1,p=0;k<n;k <<=1) 20 { 21 p=0; 22 for
(i=n-k;i<n;i++) y[p++]=i; 23 for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; 24 for(i=0;i<m;i++) cnt[i]=0; 25 for(i=0;i<n;i++) cnt[x[y[i]]]++; 26 for(i=1;i<m;i++) cnt[i]+=cnt[i-1]; 27 for(i=n-1;i>=0;i--) sa[--cnt[x[y[i]]]]=y[i]; 28 swap(x,y); 29 p=1;x[sa[0]]=0; 30 for(i=1;i<n;i++) 31 { 32 if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]) x[sa[i]]=p-1; 33 else x[sa[i]]=p++; 34 } 35 if(p>=n) break; 36 m=p; 37 } 38 } 39 void build_height() 40 { 41 int k=0; 42 for(int i=0;i<n;i++) rank[sa[i]]=i; 43 for(int i=0;i<n;i++) 44 { 45 if(k) k--; 46 if(!rank[i]) continue; 47 int j=sa[rank[i]-1]; 48 while(s[i+k]==s[j+k]) k++; 49 height[rank[i]]=k; 50 } 51 } 52 } SA; 53 54 inline void add(int ch,int id) 55 { 56 idx[SA.n]=id; 57 SA.s[SA.n++]=ch;//// 58 } 59 60 int flag[maxn]; 61 inline int check(int ans) 62 { 63 int check_clock=1; 64 memset(flag,0,sizeof(flag)); 65 for(int i=1;i<SA.n;i++) 66 { 67 if(SA.height[i]>=ans) 68 { 69 flag[idx[SA.sa[i]]]=check_clock; 70 flag[idx[SA.sa[i-1]]]=check_clock; 71 } 72 else 73 { 74 int cnt=0; 75 for(int j=0;j<n;j++) if(flag[j]==check_clock) cnt++; 76 if(cnt>n/2) return true; 77 flag[idx[SA.sa[i]]]=++check_clock; 78 } 79 } 80 return false; 81 } 82 83 inline void print_ans(int l,int r) 84 { 85 for(int i=l;i<=r;i++) printf("%c",SA.s[i]+a-1); 86 printf("\n"); 87 } 88 89 inline void print(int ans) 90 { 91 int check_clock=1; 92 memset(flag,0,sizeof(flag)); 93 for(int i=1;i<SA.n;i++) 94 { 95 if(SA.height[i]>=ans) 96 { 97 flag[idx[SA.sa[i]]]=check_clock; 98 flag[idx[SA.sa[i-1]]]=check_clock; 99 } 100 else 101 { 102 int cnt=0; 103 for(int j=0;j<n;j++) if(flag[j]==check_clock) cnt++; 104 if(cnt>n/2) print_ans(SA.sa[i-1],SA.sa[i-1]+ans-1); 105 flag[idx[SA.sa[i]]]=++check_clock; 106 } 107 } 108 } 109 char s[1000+10]; 110 int kase=0; 111 int main() 112 { 113 int maxlen; 114 while(scanf("%d",&n)==1&&n) 115 { 116 if(kase++) printf("\n"); 117 SA.clear(); 118 maxlen=0; 119 for(int i=0;i<n;i++) 120 { 121 scanf("%s",s); 122 int l=strlen(s); 123 maxlen=max(maxlen,l); 124 for(int j=0;j<l;j++) add(s[j]-a+1,i); 125 add(100+i,n); 126 } 127 if(n==1) {printf("%s\n",s);continue;} 128 SA.build_sa(101+n); 129 SA.build_height(); 130 int l=1,r=maxlen,ans=0; 131 while(l<=r) 132 { 133 int mid=((l+r)>>1); 134 if(check(mid)) ans=mid,l=mid+1; 135 else r=mid-1; 136 } 137 if(ans) print(ans); 138 else printf("?\n"); 139 } 140 return 0; 141 }
View Code

UVA-11107 Life Forms(求出現K次的子串,後綴數組+二分答案)