zoukankan      html  css  js  c++  java
  • poj 3693 Maximum repetition substring (后缀数组)

    其实是论文题。。

    题意:求一个字符串中,能由单位串repeat得到的子串中,单位串重复次数最多的子串。若有多个重复次数相同的,输出字典序最小的那个。

    解题思路:其实跟论文差不多,我看了很久没看懂,后来总算理解了一些。假设我们的单位串长度为l,那么我们将串划分为s[0] , s[l] , s[2*l] , s[3*l]。。这样,可以根据l划分为n/l段。枚举一个j,表示当前枚举的位置为s[j*l],我们要做的是,求suf[j*l]跟suf[(j+1)*l]的lcp  (这里用rmq做,询问是o(1)的),假设这个lcp是k,那我们知道,从s[j*l]开始的,以l为单位长度的repeat次数至少是k/l + 1,这是为什么呢?想想lcp的意思,应该能想通的。但这样并不一定是最优的,因为我们如果往前推,有可能还有一些是相同的,那就往前枚举i,表示前i个也是相同的,一直枚举到不同,或者额外增加的长度超过l为止(超过l就相当于是上一个j了)。这时,我们的新的lcp长度k=k+i了,用这个k去计算repeat次数才是正确的。遍历过程中,我们要把取到最大repeat次数的l记下来,求字典序最小时,就按rank从小到大枚举开头,然后看有没有记下的l中,在当前开头的字符串是符合最大repeat次数的(用lcp再判断一次好了),一旦找到符合的,就输出好了。

    没写case,一直错,一直找不到错哪儿,泪奔了。。。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    using namespace std ;
    const int maxn = 511111 ;
    
    int p[maxn] ;
    int min ( int a , int b ) { return a < b ? a : b ; }
    int dp[25][maxn] , f[maxn] , ans , fuck ;
    
    vector<int>vec ;
    struct Suf{
    	int wa[maxn] , wb[maxn] , ws[maxn] , wv[maxn] ;
    	int rank[maxn] , hei[maxn] , sa[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 , k , 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 ,x[sa[0]] = 0 , p = 1 , i = 1 ; i < n ; i ++ )
    				x[sa[i]] = cmp ( y , sa[i-1] , sa[i] , j ) ? p - 1 : p ++ ;
    		}
    		k = 0 ;
    		for ( i = 1 ; i < n ; i ++ ) rank[sa[i]] = i ;
    		for ( i = 0 ; i < n - 1 ; hei[rank[i++]] = k )
    			for ( k ? k -- : 0 , j = sa[rank[i]-1] ; r[i+k] == r[j+k] ; k ++ ) ;
    	}
    
    	void rmq ( int n ) {
    		int i , j ;
    		for ( i = 1 ; i <= n ; i ++ ) dp[0][i] = hei[i] ;
    		for ( i = 1 ; i <= 20 ; i ++ )
    			for ( j = 1 ; j + ( 1 << i ) - 1 <= n ; j ++ )
    				dp[i][j] = min ( dp[i-1][j] , dp[i-1][j+(1<<(i-1))] ) ;
    	}
    
    	int query ( int l , int r ) {
    		if ( l > r ) swap ( l , r ) ;
    		l ++ ;//要从height[l+1]到height[r]之间求最小值
    		if ( l == r ) return dp[0][l] ;
    		int k = r - l + 1 ;
    		return min ( dp[f[k]][l] , dp[f[k]][r-(1<<f[k])+1] ) ;
    	}
    
    	void solve ( int n , char *s ) {
    		rmq ( n ) ;
    		int i , j , k , l , r ;
    		for ( l = 1 ; l < n ; l ++ )
    			for ( j = 0 ; j < n / l ; j ++ ) {
    				int pos1 = j * l , pos2 = j * l + l ;
    				k = query ( rank[pos1] , rank[pos2] ) ;
    				i = 0 ;
    				if ( j != 0 ) {
    					while ( i < l && s[pos1-i-1] == s[pos2-i-1] ) i ++ ;
    				}
    				k += i ;
    				int add = k / l + 1 ;
    				if ( add == ans ) vec.push_back ( l ) ;
    				if ( add > ans ) {
    					ans = add ;
    					vec.clear () ;
    					vec.push_back ( l ) ;
    				}
    			}
    		int flag ;
    		for ( i = 1 ; i <= n ; i ++ ) {
    			flag = 0 ;
    			for ( j = 0 ; j < vec.size () ; j ++  ) {
    				l = vec[j] ;
    				k = query ( i , rank[sa[i]+l] ) ;
    				if ( k / l + 1 == ans ) {
    					for ( r = 0 ; r < ans * l ; r ++ )
    						printf ( "%c" , s[sa[i]+r] ) ;
    					puts ( "" ) ;
    					flag = 1 ;
    					break ;
    				}
    			}
    			if ( flag ) break ;
    		}
    	}
    
    } arr ;
    
    char s1[maxn] ;
    int s[maxn] ;
    
    int main () {
    	int cas , n , i , j , ca = 0 ;
    	j = 0 ;
    	for ( i = 1 ; i < maxn - 1111 ; i ++ ) {
    		if ( i > 1 << j + 1 ) j ++ ;
    		f[i] = j ;
    	}
    	scanf ( "%d" , &cas ) ;
    	while ( cas -- ) {
    		scanf ( "%s" , s1 ) ;
    		if ( s1[0] == '#' ) break ;
    		vec.clear () ;
    		ans = 1 ;
    		n = strlen ( s1 ) ;
    		int len = 0 ;
    		for ( i = 0 ; i < n ; i ++ ) s[i] = s1[i] ;
    		s[n] = 0 ;
    		arr.da ( s , n + 1 , 555 ) ;
    		printf ( "Case %d: " , ++ca ) ;
    		arr.solve ( n , s1 ) ;
    	}
    }



  • 相关阅读:
    java 泛型
    数据结构与算法分析java——线性表1
    常见链表题
    网络面试题集锦
    java 网络流 TCP/UDP
    java文件
    java IO流——字节流
    java IO流——字符流
    java集合框架——工具类
    java集合框架——Map
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3265249.html
Copyright © 2011-2022 走看看