UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)

Posted songorz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)相关的知识,希望对你有一定的参考价值。

技术分享图片

题解:

题意:

输入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("
");
 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("
");
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
",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("?
");
139     }
140     return 0;
141 }
View Code

 

以上是关于UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)的主要内容,如果未能解决你的问题,请参考以下文章

POJ 3294 UVA 11107 Life Forms 后缀数组

UVA11107 训练指南Life Forms后缀数组

UVa 11107 生命的形式(不小于k个字符串中的最长子串)

POJ 3294 Life Forms(后缀数组+二分答案)

POJ3294 Life Forms

Life Forms