您的位置:首页 > 其它

UVALive 3026 Period(KMP裸)

2015-09-07 22:56 363 查看
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1027

题意:给定长度为n的字符串S,求它每个前缀的最短循环节。

思路:对于S的一个长度为i的前缀,若这个前缀是一个周期串,则i - f[i]的部分是循环节。

如图:


已知 [1~4]和[a~d]是相等的。有f[i]的定义可知[2~5]和[1~4]是相等的,所以[2~5]和[a~d]相等。因为5和e是相等的,都是i - f[i]的部分。所以可以推导得出:d = 5 = e。

同理可以得出:c = 4 = d,b = 3 = c,a = 2 = b。

所以就可以得到a = b = c = d = e。

那么e就是循环节。

但是,前提是:

f[i]需要大于0,即存在一个非空最大前缀与i结尾的后缀相等。

i % (i - f[i]) == 0。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <stack>

using namespace std;

#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define ceil(x, y) (((x) + (y) - 1) / (y))

const int SIZE = 30;
const int N = 1e6 + 10;
const int M = 5e2 + 10;
const int INF = 0x7f7f7f7f;
const int MAX_WORD = 1e6 + 10;
const double EPS = 1e-9;
const int MOD = 2015;

int f
;
char str
;

void getfail(char *s) {
    f[0] = f[1] = 0;
    for (int i = 1; s[i]; i++) {
        int u = f[i];
        while (u && s[i] != s[u]) u = f[u];
        f[i + 1] = (s[i] == s[u] ? u + 1 : 0);
    }
}

int main() {    
    int n, i_case = 1;
    while (scanf("%d", &n) != EOF && n) {
        scanf("%s", str);
        getfail(str);
        printf("Test case #%d\n", i_case++);
        for (int i = 2; i <= n; i++)
            if (f[i] && i % (i - f[i]) == 0)
                printf("%d %d\n", i, i / (i - f[i]));
        printf("\n");
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: