后缀数组LCP + 二分 - UVa 11107 Life Forms

Life Forms 

Problem's Link


 

Mean: 

给你n个串,让你找出出现次数大于n/2的最长公共子串。如果有多个,按字典序排列输出。

analyse:

经典题。

直接二分判断答案。

判断答案p时,我们扫一遍height数组,如果height[i]<p时开辟一个新段。

判断时用set存储所在串编号,不仅起到去重的作用,而且也起到统计段长的作用。

也可以直接用字符串hash来做,也是先二分,然后O(n)判断,时间复杂度和后缀数组一样。

Time complexity: O(N*logN)

 

Source code: 

1.后缀数组:

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-09-05-14.44
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);

const int MAXLEN = 200005;
struct Suffix
{
      int s [ MAXLEN ];
      int sa [ MAXLEN ], t [ MAXLEN ], t2 [ MAXLEN ], c [ MAXLEN ], n;
      int Rank [ MAXLEN ], height [ MAXLEN ];

      void build_sa( int m)
      {
            int i , * x = t , * y = t2;
            for( i = 0; i < m; i ++) c [ i ] = 0;
            for( i = 0; i < n; i ++) c [ x [ i ] = s [ i ]] ++;
            for( i = 1; i < m; i ++) c [ i ] += c [ i - 1 ];
            for( i = n - 1; i >= 0; i --) sa [ -- c [ x [ i ]]] = i;
            for( int k = 1; k <= n; k <<= 1)
            {
                  int p = 0;
                  for( i = n - k; i < n; i ++) y [p ++ ] = i;
                  for( i = 0; i < n; i ++) if( sa [ i ] >= k) y [p ++ ] = sa [ i ] - k;
                  for( i = 0; i < m; i ++) c [ i ] = 0;
                  for( i = 0; i < n; i ++) c [ x [ y [ i ]]] ++;
                  for( i = 0; i < m; i ++) c [ i ] += c [ i - 1 ];
                  for( i = n - 1; i >= 0; i --) sa [ -- c [ x [ y [ i ]]]] = y [ i ];
                  swap( x , y);
                 p = 1; x [ sa [ 0 ]] = 0;
                  for( i = 1; i < n; i ++)
                        x [ sa [ i ]] = y [ sa [ i - 1 ]] == y [ sa [ i ]] && y [ sa [ i - 1 ] + k ] == y [ sa [ i ] + k ] ? p - 1 : p ++;
                  if(p >= n) break;
                  m = p;
            }
      }

      void getHeight()
      {
            int i , j , k = 0;
            for( i = 0; i < n; i ++) Rank [ sa [ i ]] = i;
            for( i = 0; i < n; i ++)
            {
                  if( k) k --;
                  if( Rank [ i ] == 0) continue;
                  int j = sa [ Rank [ i ] - 1 ];
                  while(s [ i + k ] == s [ j + k ]) k ++;
                  height [ Rank [ i ]] = k;
            }
      }
} Suf;

const int N = 1005;

int n , l , r , id [ MAXLEN ];
char str [N ];

bool judge( int x , int bo)
{
      set < int > vis;
      vis . insert( id [ Suf . sa [ 1 ]]);
      for( int i = 2; i < Suf .n; i ++)
      {
            while( i < Suf .n && Suf . height [ i ] >= x)
            {
                  vis . insert( id [ Suf . sa [ i ]]);
                  i ++;
            }
            if( vis . size() * 2 > n)
            {
                  if( bo == 0)
                        return true;
                  for( int j = 0; j < x; j ++)
                        printf( "%c" , Suf .s [ Suf . sa [ i - 1 ] + j ]);
                  printf( " \n ");
            }
            vis . clear();
            vis . insert( id [ Suf . sa [ i ]]);
      }
      return false;
}

void solve()
{
      if( ! judge( 1 , 0))
      {
            printf( "? \n ");
            return;
      }
      l = 1; r ++;
      while( l < r)
      {
            int mid = ( l + r) / 2;
            if( judge( mid , 0)) l = mid + 1;
            else r = mid;
      }
      l --;
      judge( l , 1);
}

int main()
{
      int bo = 0;
      while( ~ scanf( "%d" , &n) && n)
      {
            if( bo) printf( " \n ");
            else bo = 1;
            if(n == 1)
            {
                  scanf( "%s" , str);
                  printf( "%s \n " , str);
                  continue;
            }
            int tot = 0;
            r = 0;
            for( int i = 0; i < n; i ++)
            {
                  scanf( "%s" , str);
                  int len = strlen( str);
                  r = max( len , r);
                  for( int j = 0; j < len; j ++)
                  {
                        id [ tot ] = i;
                        Suf .s [ tot ++ ] = str [ j ];
                  }
                  id [ tot ] = i;
                  Suf .s [ tot ++ ] = 'z' + i + 1;
            }
            Suf .n = tot;
            Suf . build_sa( 'z' + n + 1);
            Suf . getHeight();
            solve();
      }
      return 0;
}

2.字符串hash:

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-09-03-12.21
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);

const int MAXN = 10001010 , seed = 173;
int n , id [ MAXN ];
char s [ MAXN ], str [ 5010 ];
vector < pair < int , int > > same;
int getBegin( int st , int en)
{
      for( int i = 0; i < same . size(); ++ i)
            if( st >=(( & same [ i ]) -> first) &&   en <=(( & same [ i ]) -> second))
                  return ( & same [ i ]) -> first;
      return - 1;
}

vector < string > ans;
bool judge( int p , bool ty)
{
      vector < pair < ULL , pair < int , int > > > v;
      ULL hv = 0 , base = 1;
      for( int i = 0; i <p; ++ i)
      {
            hv = hv * seed +s [ i ];
            base *= seed;
      }
      v . push_back( make_pair( hv , make_pair( 0 ,p - 1)));
      int len = strlen(s);
      for( int i =p; i < len; ++ i)
      {
            hv = hv * seed +s [ i ] - base *s [ i -p ];
            if( getBegin( i -p + 1 , i) !=- 1)
                  v . push_back( make_pair( hv , make_pair( i -p + 1 , i)));
      }
      sort( v . begin (), v . end());
      set < int > id;
      int st , en , cnt;
      bool f = false;
      ans . clear();
      auto p1 = v . begin (), p2 = v . begin();
      ++ p2;
      for(; p2 != v . end(); ++ p1 , ++ p2)
      {
            if( p2 -> first != p1 -> first) id . clear();
            else
            {

                  while( p2 -> first == p1 -> first)
                  {
                        st =( & p2 -> second) -> first;
                        en =( & p2 -> second) -> second;
                        if( getBegin( st , en) !=- 1 &&
                          getBegin(( & p1 -> second) -> first ,( & p1 -> second) -> second) !=- 1 &&
                          id . find( getBegin( st , en)) == id . end() &&
                          getBegin(( & p1 -> second) -> first ,( & p1 -> second) -> second) != getBegin( st , en))
                        {
                              id . insert( getBegin( st , en));
                        }
                        ++ p1 , ++ p2;
                  }
                  -- p1 , -- p2;
                  if(( id . size() + 1) * 2 >n)
                  {
                        f = true;
                        st =( & p2 -> second) -> first;
                        en =( & p2 -> second) -> second;
                        cnt = 0;
                        for( int i = st; i <= en; ++ i)
                              str [ cnt ++ ] =s [ i ];
                        str [ cnt ] = '\0';
                        ans . push_back( str);
                        id . clear();
                  }
            }
      }
      if( ! ty) return f;
      sort( ans . begin (), ans . end());
      for( int i = 0; i < ans . size(); ++ i)
            printf( "%s \n " , ans [ i ]. c_str());
}


int main()
{
      int Cas = 0;
      while( ~ scanf( "%d" , &n) && n)
      {
            if( Cas ++) puts( "");
            if(n == 1)
            {
                  scanf( "%s" ,s);
                  puts(s);
                  continue;
            }
            same . clear();
            int maxLen = 0 , st , en;
            memset(s , 0 , sizeof s);
            for( int i = 0; i <n; ++ i)
            {
                  scanf( "%s" , str);
                  st = strlen(s);
                  maxLen = max( maxLen ,( int) strlen( str));
                  strcat(s , str);
                  en = strlen(s);
                  same . push_back( make_pair( st , en - 1));
            }
            if( ! judge( 1 , 0))
            {
                  puts( "?");
                  continue;
            }
            int l = 1 , r = maxLen , mid;
            while( r > l + 1)
            {
                  mid = l +( r - l) / 2;
                  if( judge( mid , 0)) l = mid;
                  else r = mid;
            }
            judge( l , 1);
      }
      return 0;
}
/*

*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值