spoj687 Repeats

REPEATS - Repeats

Description

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.

Sample Input

1
17
b
a
b
b
a
b
a
a
b
a
a
b
a
a
b
a
b

Sample Output

4

题目大意

给定一个字符串,问其字串最多能重复多少次。

题解

论文题。
考虑一个子串S是由长度为L的子串连续重复构成的,那么,S肯定包括了字符s[0],s[L],s[L*2],s[L*3]…中某相邻的两个(甚至更多)。所以枚举s[L*i]和s[L*(i+1)]往后可以匹配多远,必然可以出现s[L*i]在第一个循环节里,而s[L*(i+1)]在第二个循环节里的这种情况,如果此时s[L*i]是第一个循环节的首字符,这样直接用公共前缀k除以i并向下取整就可以得到最后结果。但如果s[L*i]如果不是首字符,这样算完之后结果就有可能偏小,因为s[L*i]前面可能还有少许字符也能看作是第一个循环节里的。
于是,从s[L*i]开始,除匹配了k/L个循环节,还剩余了几个字符,剩余的自然是k%L个字符。如果说s[L*i]的前面还有L-k%L个字符完成比配的话,这样就相当于还可以再匹配出一个循环节,于是我们只要检查一下从s[L*i-(L-k%L)]和s[L*i-(L-k%L)+L]开始是否有i-k%i个字符能够完成匹配即可,也就是说去检查这两个后缀的最长公共前缀是否比i-k%i大即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#define min(x, y) ((x) < (y) ? (x) : (y))
using namespace std;

const int N = 50000 + 10;
int n, a[N], sa[2][N], rk[2][N], ht[N], v[N];
int p, q, k;
int st[N][20], mn[N];
int ans;

void init(){
    memset(a, 0, sizeof(a));memset(v, 0, sizeof(v));
    memset(sa, 0, sizeof(sa));memset(rk, 0, sizeof(rk));memset(ht, 0, sizeof(ht));
    memset(st, 0, sizeof(st));
    ans = 0;
    scanf("%d", &n);
    char s[10];
    for(int i = 1; i <= n; i++){
        scanf("%s", s);
        a[i] = (char) s[0];
    }
}

void calsa(int *sa1, int *rk1, int *sa2, int *rk2){
    for(int i = 1; i <= n; i++) v[rk1[sa1[i]]] = i;
    for(int i = n; i >= 1; i--) if(sa1[i] > k) sa2[v[rk1[sa1[i]-k]]--] = sa1[i] - k;
    for(int i = n-k+1; i <= n; i++) sa2[v[rk1[i]]--] = i;
    for(int i = 1; i <= n; i++) rk2[sa2[i]] = rk2[sa2[i-1]] +
        (rk1[sa2[i-1]] != rk1[sa2[i]] || rk1[sa2[i-1]+k] != rk1[sa2[i]+k]);
}

void calht(){
    int k = 0;
    for(int i = 1; i <= n; i++){
        if(k) k--;
        int j = sa[p][rk[p][i]-1];
        while(a[i+k] == a[j+k]) k++;
        ht[rk[p][i]] = k;
    }
}

void calst(){
    mn[0] = -1;
    for(int i = 1; i <= n; i++){
        mn[i] = (i & i-1) ? mn[i-1] : mn[i-1] + 1;
        st[i][0] = ht[i];
    }
    for(int j = 1; j <= mn[n]; j++)
        for(int i = 1; i + (1<<j) - 1 <= n; i++)
         st[i][j] = min(st[i][j-1], st[i+(1<<j-1)][j-1]);
}

int calmn(int x, int y){
    if(x > y) swap(x, y);
    x++;
    int k = mn[y-x+1];
    return min(st[x][k], st[y-(1<<k)+1][k]);
}

int cal(int x, int y){
    int l = rk[p][x], r = rk[p][y];
    return calmn(l, r);
}

void work(){
    p = 0, q = 1, k = 1;
    for(int i = 1; i <= n; i++) v[a[i]]++;
    for(int i = 1; i <= 130; i++) v[i] += v[i-1];
    for(int i = 1; i <= n; i++) sa[p][v[a[i]]--] = i;
    for(int i = 1; i <= n; i++) rk[p][sa[p][i]] = rk[p][sa[p][i-1]] + (a[sa[p][i]] != a[sa[p][i-1]]);
    memset(v, 0, sizeof(v));
    while(k < n){
        calsa(sa[p], rk[p], sa[q], rk[q]);
        p ^= 1, q ^= 1, k <<= 1;
    }
    calht();
    calst();
    for(int i = 1; i <= n; i++){
        for(int j = 1; j + i <= n; j += i){
            int tmp = cal(j, j+i);
            int k = j - (i - tmp % i);
            tmp = tmp / i + 1;
            if(k >= 1 && cal(k, k + i) >= i)
                tmp++;
            ans = max(ans, tmp);
        }
    }
    printf("%d\n", ans);
}

int main(){
    int t; scanf("%d", &t);
    while(t--){
        init();
        work();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
洛谷的SPOJ需要注册一个SPOJ账号并进行绑定才能进行交题。您可以按照以下步骤进行注册: 1. 打开洛谷网站(https://www.luogu.com.cn/)并登录您的洛谷账号。 2. 在网站顶部导航栏中找到“题库”选项,将鼠标悬停在上面,然后选择“SPOJ”。 3. 在SPOJ页面上,您会看到一个提示,要求您注册SPOJ账号并进行绑定。点击提示中的链接,将会跳转到SPOJ注册页面。 4. 在SPOJ注册页面上,按照要求填写您的用户名、密码和邮箱等信息,并完成注册。 5. 注册完成后,返回洛谷网站,再次进入SPOJ页面。您会看到一个输入框,要求您输入刚刚注册的SPOJ用户名。输入用户名后,点击“绑定”按钮即可完成绑定。 现在您已经成功注册并绑定了SPOJ账号,可以开始在洛谷的SPOJ题库上刷题了。祝您顺利完成编程练习!\[1\]\[2\] #### 引用[.reference_title] - *1* *3* [(洛谷入门系列,适合洛谷新用户)洛谷功能全解](https://blog.csdn.net/rrc12345/article/details/122500057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [luogu p7492 序列](https://blog.csdn.net/zhu_yin233/article/details/122051384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值