Repeats spoj 687 后缀数组求重复次数最多的连续重复子串

版权声明:转载请标明出处 https://blog.csdn.net/weixin_41190227/article/details/86565615

A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed string t with length l>=1. For example, the string

s = abaabaabaaba

is a (4,3)-repeat with t = aba as its seed string. That is, the seed string t is 3 characters long, and the whole string s is obtained by repeating t 4 times.

Write a program for the following task: Your program is given a long string u consisting of characters ‘a’ and/or ‘b’ as input. Your program must find some (k,l)-repeat that occurs as substring within u with k as large as possible. For example, the input string

u = babbabaabaabaabab

contains the underlined (4,3)-repeat s starting at position 5. Since u contains no other contiguous substring with more than 4 repeats, your program must output the maximum k.

Input

In the first line of the input contains H- the number of test cases (H <= 20). H test cases follow. First line of each test cases is n - length of the input string (n <= 50000), The next n lines contain the input string, one character (either ‘a’ or ‘b’) per line, in order.

Output

For each test cases, you should write exactly one interger k in a line - the repeat count that is maximized.

Example

Input:
1
17
b
a
b
b
a
b
a
a
b
a
a
b
a
a
b
a
b

Output:
4

since a (4, 3)-repeat is found starting at the 5th character of the input string.

题目大意: 求给出的字符串中重复次数最多的连续重复子串。

解题思路:先枚举长度l, 然后求长度为l的子串最多能里连续出现几次。首先连续出现1次是肯定可以的,所以这里指考虑至少2次的情况。假设在原字符串中连续出现2次,记这个子字符串为s,那么肯定包括了r[0], r[l,], r[l * 2], r[l * 3]......中的某个相邻的两个。所以只需要看字符r[l * i] 和r[l *(i + 1)] 往前和往后各能匹配多远,记这个总长度为k, 那么这里连续出现了k/l + 1次。最后看最大值是多少即可。

在对求见查询的时候,需要用到RMQ算法。

因为是正好写到了这个题,才去现学的RMQ,所以,刚开始写的有些偏差,一直RE。。。

/*
@Author: Top_Spirit
@Language: C++
*/
#include <bits/stdc++.h>
using namespace std ;
typedef unsigned long long ull ;
typedef long long ll ;
const int Maxn = 5e4 + 10 ;
const int INF = 0x3f3f3f3f ;
const ull seed = 133 ;
const double PI = acos(-1.0) ;

int sa[Maxn],Rank[Maxn],height[Maxn];
int wa[Maxn],wb[Maxn],Ws[Maxn],wv[Maxn];
char str[Maxn];
int n ;

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

void get_sa (int *r,int n,int m){
    int i , j, p , *x = wa,*y = wb,*t;
    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 < n; i++) wv[i] = x[y[i]];
        for (i = 0; i < m; i++) Ws[i] = 0;
        for (i = 0; i < n; i++) Ws[wv[i]]++;
        for (i = 0; i < m; i++) Ws[i] += Ws[i - 1];
        for (i = n - 1; i >= 0; i--) sa[--Ws[wv[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++;
        }
    }
}
void get_height(int *r,int n){
    int k = 0, j ;
    for (int i = 1 ;i <= n; i++) Rank[sa[i]] = i;
    for (int i = 0; i < n; height[Rank[i++]] = k){
        for (k ? k-- : 0, j = sa[Rank[i] - 1]; r[i + k] == r[j + k]; k++);
    }
}

int a[Maxn] ;
int dp[Maxn][20] ;

void rmqInit(){
    for  (int i = 1; i <= n; i++) dp[i][0] = height[i] ;
    int m=(int)(log(n*1.0)/log(2.0));
    for (int j = 1; j <= m; j++){
        for (int i = 1; i + (1 << j) - 1 <= n; i++){
            dp[i][j] = min(dp[i][j - 1], dp[i + (1 << j - 1)][j - 1]) ;
        }
    }
}

int getRmq(int x, int y){
    int l = Rank[x], r = Rank[y] ;
    if (l > r) swap(l ,r) ;
    l++ ;
    int k=int(log(r-l+1.0)/log(2.0));
	return min(dp[l][k],dp[r -(1 << k) + 1][k]);
}

int main (){
    int T ;
    scanf("%d", &T) ;
    while (T--){
        scanf("%d", &n) ;
        for (int i = 0; i < n; i++){
            scanf("%s", str) ;
            a[i] = str[0] ;
        }
//        a[n] = 0 ;
        get_sa(a, n + 1, 300) ;
        get_height(a, n) ;
        rmqInit() ;
        int Max = 0 ;
        for (int i = 1; i <= n; i++){
            for (int j = 0; j + i < n; j += i){
				int tmp = getRmq(j, j + i), k = j - (i - tmp % i ) ;
				tmp = tmp / i + 1 ;
				if (k >= 0 && getRmq(k, k + i) >= i) tmp++;
				Max = max(Max, tmp) ;
			}
        }
        cout << Max << endl ;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41190227/article/details/86565615