主要思路
这道题要求在一个循环前缀中求出最小周期长度和最大频率。我们可以用 KMP 的 next 数组来解这个问题。我们先来回顾一下 next 数组的含义。\(next[i]\)代表在区间\(str[1,i]\)中前缀后缀的最长公共部分。如果区间长度是\(next[i]\)的倍数,那么其中就有循环节。详细见代码。
代码
// POJ1961.cpp
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1000000 + 1000;
int next[maxn];
string str;
int main()
{
int siz = 0, cnt = 1;
while (scanf("%d", &siz) && siz != 0)
{
cin >> str;
// get the next array;
next[0] = -1;
for (int i = 1; i < siz; i++)
{
int j = next[i - 1];
while (j >= 0 && str[i] != str[j + 1])
j = next[j];
if (str[i] == str[j + 1])
next[i] = j + 1;
else
next[i] = -1;
}
for (int i = 0; i < siz; i++)
++next[i];
// we have got it...;
printf("Test case #%d\n", cnt++);
for (int i = 1; i < siz; i++)
if ((i + 1) % (i - next[i] + 1) == 0 && (i + 1) / (i - next[i] + 1) > 1)
printf("%d %d\n", i + 1, (i + 1) / (i - next[i] + 1));
puts("");
}
return 0;
}
// POJ1961.cpp
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1000000 + 1000;
int next[maxn];
string str;
int main()
{
int siz = 0, cnt = 1;
while (scanf("%d", &siz) && siz != 0)
{
cin >> str;
// get the next array;
next[0] = -1;
for (int i = 1; i < siz; i++)
{
int j = next[i - 1];
while (j >= 0 && str[i] != str[j + 1])
j = next[j];
if (str[i] == str[j + 1])
next[i] = j + 1;
else
next[i] = -1;
}
for (int i = 0; i < siz; i++)
++next[i];
// we have got it...;
printf("Test case #%d\n", cnt++);
for (int i = 1; i < siz; i++)
if ((i + 1) % (i - next[i] + 1) == 0 && (i + 1) / (i - next[i] + 1) > 1)
printf("%d %d\n", i + 1, (i + 1) / (i - next[i] + 1));
puts("");
}
return 0;
}
// POJ1961.cpp #include <iostream> #include <cstdio> using namespace std; const int maxn = 1000000 + 1000; int next[maxn]; string str; int main() { int siz = 0, cnt = 1; while (scanf("%d", &siz) && siz != 0) { cin >> str; // get the next array; next[0] = -1; for (int i = 1; i < siz; i++) { int j = next[i - 1]; while (j >= 0 && str[i] != str[j + 1]) j = next[j]; if (str[i] == str[j + 1]) next[i] = j + 1; else next[i] = -1; } for (int i = 0; i < siz; i++) ++next[i]; // we have got it...; printf("Test case #%d\n", cnt++); for (int i = 1; i < siz; i++) if ((i + 1) % (i - next[i] + 1) == 0 && (i + 1) / (i - next[i] + 1) > 1) printf("%d %d\n", i + 1, (i + 1) / (i - next[i] + 1)); puts(""); } return 0; }