zoukankan      html  css  js  c++  java
  • poj3294 Life Forms(后缀数组)

     

    【题目链接】

     

      http://poj.org/problem?id=3294 

     

    【题意】

     

      多个字符串求出现超过R次的最长公共子串。

     

    【思路】

        

           二分+划分height,判定一个组中是否包含不小于R个不同字符串的后缀

           需要注意的有:

         1)      c[]尽量开大,字符范围为“偏移”之后的范围。

         2)      用kase作为标记节省了每次开始新段需要清零的时间。

         3)      因为height是sa[i]与sa[i-1]的关系,所以无论是在can的开始还是在新段开始都需要初始为一个串的情况。

    【代码】

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<vector>
      4 #include<iostream>
      5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
      6 using namespace std;
      7 
      8 const int maxn = 200000+10;
      9 
     10 int s[maxn];
     11 int sa[maxn],c[maxn],t[maxn],t2[maxn];
     12 
     13 void build_sa(int m,int n) {
     14     int i,*x=t,*y=t2;
     15     for(i=0;i<m;i++) c[i]=0;
     16     for(i=0;i<n;i++) c[x[i]=s[i]]++;
     17     for(i=1;i<m;i++) c[i]+=c[i-1];
     18     for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
     19     
     20     for(int k=1;k<=n;k<<=1) {
     21         int 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         
     25         for(i=0;i<m;i++) c[i]=0;
     26         for(i=0;i<n;i++) c[x[y[i]]]++;
     27         for(i=0;i<m;i++) c[i]+=c[i-1];
     28         for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
     29         
     30         swap(x,y);
     31         p=1; x[sa[0]]=0;
     32         for(i=1;i<n;i++) 
     33             x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
     34         if(p>=n) break;
     35         m=p;
     36     }
     37 }
     38 int rank[maxn],height[maxn];
     39 void getHeight(int n) {
     40     int i,j,k=0;
     41     for(i=0;i<=n;i++) rank[sa[i]]=i;
     42     for(i=0;i<n;i++) {
     43         if(k) k--;
     44         j=sa[rank[i]-1];
     45         while(s[j+k]==s[i+k]) k++;
     46         height[rank[i]]=k;
     47     }
     48 }
     49 
     50 int T;
     51 char a[maxn];
     52 
     53 int f[200],kase;
     54 vector<int> st;
     55 int can(int limit,int n,int len) {
     56     int cnt=1,ok=0;
     57     st.clear();
     58     f[sa[1]/len]=kase;
     59     for(int i=2;i<=n;i++) {
     60         if(height[i]<limit) {
     61             cnt=1;
     62             f[sa[i]/len]=++kase;               //检查每一个组中 
     63         }
     64         else {
     65             if(f[sa[i]/len]!=kase) {
     66                 f[sa[i]/len]=kase;
     67                 if(cnt>=0) cnt++;
     68                 if(cnt>T/2) {
     69                     ok=1;
     70                     st.push_back(sa[i]);
     71                     cnt=-1;
     72                 }
     73             }
     74         }
     75     }
     76     return ok;
     77 }
     78 void init() {
     79     kase=1;
     80     memset(sa,0,sizeof(sa));
     81     memset(f,0,sizeof(f));
     82 }
     83 int main() {
     84     //freopen("in.in","r",stdin);
     85     //freopen("out.out","w",stdout);
     86     while(scanf("%d",&T)==1 && T) {
     87         init();
     88         int len,n=0;
     89         for(int i=0;i<T;i++) {
     90             scanf("%s",&a);
     91             len=strlen(a);
     92             for(int j=0;j<len;j++) s[n++]=a[j]+100;
     93             s[n++]=i+1;
     94         }
     95         n--;
     96         s[n]=0;
     97         
     98         build_sa(250,n+1);
     99         getHeight(n);
    100         
    101         int L=0,R=len+1;
    102         while(L<R) {
    103             int M=L+(R-L+1)/2;
    104             if(can(M,n,len+1)) L=M;
    105             else R=M-1;
    106         }
    107         can(L,n,len+1);                        //再调用一次求出st 
    108         if(L==0) printf("?
    ");
    109         else {
    110             for(int i=0;i<st.size();i++)  {
    111                 for(int j=st[i];(j-st[i]+1)<=L;j++)
    112                     printf("%c",s[j]-100);
    113                 putchar('
    ');
    114             }
    115         }
    116         putchar('
    ');
    117     }
    118     return 0;
    119 }
  • 相关阅读:
    python gevent(协程模块)
    python基础之socket与socketserver
    python 使用 with open() as 读写文件
    Python logger模块
    python二维码操作:QRCode和MyQR入门
    常见的端口号及其用途
    python中hasattr()、getattr()、setattr()函数的使用
    mysql数据库自带数据库介绍
    关于BeautifulSoup4 解析器的说明
    学习opencv(1)
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5004442.html
Copyright © 2011-2022 走看看