题意:给出字符串,求循环同构字符串的最小最大字典序,以及两者的出现次数。
题解:最小\最大表示法+kmp
循环节长度:
l
e
n
−
n
x
t
[
l
e
n
]
len-nxt[len]
len−nxt[len]
循环节出现次数:
l
e
n
/
(
l
e
n
−
n
x
t
[
i
]
)
len/(len-nxt[i])
len/(len−nxt[i]),前提是能整除。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#define ll long long
using namespace std;
const int MAXN = 1e6 + 10;
char s[MAXN];
int len;
int solve(char* code, int m, int flag) { //1为最小表示
int k = 0, i = 0, j = 1;
while (k < m && i < m && j < m) {
if (code[(i + k) % m] == code[(j + k) % m]) {
k++;
}
else {
if(flag) code[(i + k) % m] > code[(j + k) % m] ? i = i + k + 1 : j = j + k + 1;
else code[(i + k) % m] < code[(j + k) % m] ? i = i + k + 1 : j = j + k + 1;
if (i == j) i++;
k = 0;
}
}
i = min(i, j);
return i;
}
int nxt[MAXN];
void kmp_pre(char x[], int m, int Next[]) { //下标从0开始
int i, j;
j = Next[0] = -1;
i = 0;
while (i < m) {
while (-1 != j && x[i] != x[j])j = Next[j];
Next[++i] = ++j;
}
}
string last;
int main() {
while (~scanf("%s", s)) {
len = strlen(s);
int fi = solve(s, len, 1) + 1;
int la = solve(s, len, 0) + 1;
kmp_pre(s, len, nxt);
int a = len % (len - nxt[len]) ? 1 : len / (len - nxt[len]);
printf("%d %d %d %d\n", fi, a, la, a);
}
return 0;
}