UVA1328题解

前置知识:KMP

本蒟蒻已经默认大佬们会了 KMP


我们来看一下这道题:

设 $nxt_i$ 表示 $A$ 中以 $i$ 为结尾的非前缀子串与 $A$ 的前缀 能够匹配的最长长度,即:

$nxt_i = \max(j)$,其中 $j < i$ 并且 $A_{i - j + 1}$ ~ $A_i = A_1$ ~ $A_j$

$nxt_i$是 KMP 的精髓,不在讲述。

显然,若 $i - nxt_i$ 能被 $i$ 整除时, $A_1$ ~ $A_{nxt_i}$ 就是 $A_1$ ~ $A_i$ 的最小循环元,那么它的最大循环次数是 $i / (i - nxt_i)$。

其中,$i - nxt_i$ 能整除 $i$ 的条件是为了保证循环元每次重复的完整性

具体实现,请看代码。

#include <iostream>
using namespace std;

const int maxn = 1000010;
char a[maxn];
int nxt[maxn], n, t;

void calc () {
    nxt[1] = 0;
    for (int i = 2, j = 0; i <= n; ++i) {
        while (j > 0 && a[i] != a[j + 1]) j = nxt[j];
        if (a[i] == a[j + 1]) j ++;
        nxt[i] = j; 
    }
}

int main() {
    while (scanf ("%d", &n) != EOF && n) {
        scanf ("%s", a + 1);
        calc (); // 计算 nxt[i]
        printf ("Test case #%d\n", ++t);// 注意输出
        for (int i = 2; i <= n; ++i) {
            if (i % (i - nxt[i]) == 0 && i / (i - nxt[i]) > 1) {
                printf ("%d %d\n", i, i / (i - nxt[i]));
            }
        }
        printf ("\n");
    }
    return 0;
}
posted @ 2021-06-12 22:23  wangzhongyuan  阅读(1)  评论(0编辑  收藏  举报  来源