您的位置:首页 > Web前端

poj 3294 Life Forms (后缀数组)

2013-08-14 16:17 405 查看
poj 3294 Life Forms

题意:给出n个字符串,问这n个字符串中,一半以上字符串拥有的最长连续公共子串有多少,按字典序全部输出来。

解题思路:一般这种最长连续公共子串什么的都是后缀数组,二分答案。。先将n个字符连起来,预处理一遍,sa,rank,height都算出来(这些我都放在模板里),然后就是二分答案了。在判断某个长度是否符合要求时,根据height值,将按height值排序的后缀划分成若干段,划分的依据就是,height[i] < key ,那么l[++tot] = i - 1 ,即到i-1为止多了一个区间。划分好之后,就是看每一个区间里,后缀中,长为key的的前缀的来源是否超过n/2,若超过n/2,那么这个前缀就是可以的,每一个区间的长为key的前缀肯定是不一样的(否则就会被分到同同一个区间了),对于按字典序输出,其实我们这样一个个加进去就已经是字典序了,height就是按字典序排的。然后就是找这些前缀的来源了,对于枚举到的某一后缀i,我们根据sa[i],就可以找到它来自哪个字符串,很多题解说是要加一个字符来划分这n个字符串,其实只要根据长度不就可以划分了么?预处理val[i],表示连接起来后,第i个字符串结尾的后一位在哪儿,然后查找某一后缀时,二分就可以找到它是属于哪个字符串了。还有就是对于sa[i]
+ key > val[k](k表示枚举到得第i个后缀的头一个字符是哪一个字符串里德)是不能被计算进去的,也不用进行任何的处理,跳过就好了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std ;

const int maxn = 111111 ;

int max ( int a , int b ) { return a > b ? a : b ; }
int min ( int a , int b ) { return a < b ? a : b ; }

int val[maxn] , vis[maxn] , n , ans = 0 , len , f[maxn] ;

char s1[maxn] ;
int s[maxn] ;

vector<int> vec ;
vector<int> fuck ;

int wa[maxn] , wb[maxn] , wv[maxn] , ws[maxn] , l[maxn] ;
struct suf
{
	int sa[maxn] , hei[maxn] , rank[maxn] ;

	int cmp ( int *r , int i , int j , int l )
	{
		return r[i] == r[j] && r[i+l] == r[j+l] ;
	}

	void da ( int *r , int n , int m )
	{
		int *x = wa , *y = wb , *t ;
		int i , j , p ;
		for ( i = 0 ; i < m ; i ++ ) ws[i] = 0 ;
		for ( i = 0 ; i < n ; i ++ ) ws[x[i]=r[i]] ++ ;
		for ( i = 1 ; i < m ; i ++ ) ws[i] += ws[i-1] ;
		for ( i = n - 1 ; i >= 0 ; i -- ) sa[--ws[x[i]]] = i ;
		for ( j = 1 , p = 1 ; p < n ; j *= 2 , m = p )
		{
			for ( p = 0 , i = n - j ; i < n ; i ++ ) y[p++] = i ;
			for ( i = 0 ; i < n ; i ++ ) if ( sa[i] >= j ) y[p++] = sa[i] - j ;
			for ( i = 0 ; i < m ; i ++ ) ws[i] = 0 ;
			for ( i = 0 ; i < n ; i ++ ) ws[x[i]] ++ ;
			for ( i = 1 ; i < m ; i ++ ) ws[i] += ws[i-1] ;
			for ( i = n - 1 ; i >= 0 ; i -- ) sa[--ws[x[y[i]]]] = y[i] ;
			for ( t = x , x = y , y = t , p = 1 , x[sa[0]] = 0 , i = 1 ; i < n ; i ++ )
				x[sa[i]] = cmp ( y , sa[i-1] , sa[i] , j ) ? p - 1 : p ++ ;
		}
		int k = 0 ;
		for ( i = 1 ; i < n ; i ++ ) rank[sa[i]] = i ;//这里sa[0]不用加进去了
		for ( i = 0 ; i < n - 1 ; hei[rank[i++]] = k )//同上,rank[n-1]=0
			for ( k ? k -- : 0 , j = sa[rank[i]-1] ; r[i+k] == r[j+k] ; k ++ ) ;
	}

	int judge ( int key ) {
		int i , j ;
		fuck.clear () ;
		int k = f[1] ;
		for ( i = 0 ; i <= n ; i ++ ) vis[i] = 0 ;
		int tot = 0 ;
		for ( i = 2 ; i <= len ; i ++ ) {
			if ( hei[i] < key )
				l[++tot] = i -1 ;
		}
		l[++tot] = len ;
		int top = 1 , cnt = 0 ;
		for ( i = 1 ; i <= len ; i ++ ) {
			k = f[i] ;
			if ( sa[i] + key <= val[k] && !vis[k] ) cnt ++ , vis[k] = 1 ;
			if ( i == l[top] ) {
				if ( cnt > ( n >> 1 ) ) fuck.push_back ( sa[i] ) ;
				top ++ ;
				for ( j = 0 ; j <= n ; j ++ ) vis[j] = 0 ;
				cnt = 0 ;
			}
		}
		k = fuck.size () ;
		if  ( k ) { 
			ans = key ;
			vec = fuck ;
		}
		return k ;
	}

} arr ;
int main () {
	int i , j , k , flag = 0 ;
	while ( scanf ( "%d" , &n ) != EOF ) {
		if ( n == 0 ) break ;
		len = 0 ;
		vec.clear () ;
		for ( i = 1 ; i <= n ; i ++ ) {
			scanf ( "%s" , s1 ) ;
			val[i] = strlen ( s1 ) ;
			for ( j = 0 ; j < val[i] ; j ++ )
				s[len++] = s1[j] ;
		}
		for ( i = 2 ; i <= n ; i ++ )
			val[i] += val[i-1] ;
		s[len] = 0 ;
		if ( flag ) puts ( "" ) ;
		flag = 1 ;
		if ( n == 1 ) {
			for ( i = 0 ; i < len ; i ++ )
				printf ( "%c" , s[i] ) ;
			puts ( "" ) ;
			continue ;
		}
		arr.da ( s , len + 1 , 555 ) ;
		for ( i = 1 ; i <= len ; i ++ )
			f[i] = upper_bound ( val + 1 , val + n + 1 , arr.sa[i] ) - val ;
		int l = 1 , r = len ;
		while ( l <= r ) {
			int m = ( l + r ) >> 1 
			if ( arr.judge ( m ) ) l = m + 1 ;
			else r = m - 1 ;
		}
		if ( vec.size () == 0 ) puts ( "?" ) ;
		else{
			int l = vec.size () ;
			for ( i = 0 ; i < l ; i ++ ) {
				for ( j = 0 ; j < ans ; j ++ )
					printf ( "%c" , s[vec[i]+j] ) ;
				puts ( "" ) ;
			}
		}
	}
}
/*
5
bbaba
babaa
ccaca
accac
bccac
5
aabbcc
ccaabb
ccaacc
bbddaa
abcde
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: