• 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
  • 相关阅读:
    一只简单的网络爬虫(基于linux C/C++)————Url处理以及使用libevent进行DNS解析
    一只简单的网络爬虫(基于linux C/C++)————浅谈并发(IO复用)模型
    一只简单的网络爬虫(基于linux C/C++)————支持动态模块加载
    一只简单的网络爬虫(基于linux C/C++)————守护进程
    培训班出身的程序员怎么了
    【技术人成长】知识铺
    几篇QEMU/KVM代码分析文章
    用callgraph生成的两张函数调用关系图
    Qemu对x86静态内存布局的模拟
    KVM技术
  • 原文地址:https://www.cnblogs.com/csushl/p/10035525.html
Copyright © 2020-2023  润新知