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 */