题解 P1368 【工艺 /【模板】最小表示法】
怎么没人用 Lyndon 分解求最小表示法呢?它这么冷门的嘛...
Lyndon 串
对于一个字符串,若其本身就是其最小后缀,则称它为 Lyndon 串。
形式化地,对于长度为
Lyndon 分解
任意一个字符串都可以被唯一的分解成若干个字典序非严格递减的 Lyndon 串。
形式化地,对于长度为
Duval 算法
Duval 算法可以在
维护三个指针
考虑
【模板】P6114 【模板】Lyndon 分解
const int N = 5e6 + 7;
int n, ans;
char s[N];
int main() {
rds(s, n);
int i = 1;
while (i <= n) {
int j = i, k = i + 1;
while (k <= n && s[j] <= s[k]) j = s[j] == s[k++] ? j + 1 : i;
while (i <= j) i += k - j, ans ^= i - 1;
}
print(ans);
return 0;
}
最小表示法
一个字符串的最小表示定义为其所有循环同构中字典序最小的串。
形式化地,对于长度为
最小表示法可以使用 Lyndon 分解求出。
对于长度为
【模板】P1368 工艺 /【模板】最小表示法
const int N = 6e5 + 7;
int n, ans, s[N];
int main() {
rd(n);
for (int i = 1; i <= n; i++) rd(s[i]), s[i+n] = s[i];
int i = 1;
while (i <= n) {
int j = i, k = i + 1;
while (k <= n * 2 && s[j] <= s[k]) j = s[j] == s[k++] ? j + 1 : i;
while (i <= j) i += k - j, ans = i <= n ? i : ans;
}
if (ans == 0) ans = n;
for (int i = 1; i <= n; i++) print(s[ans-1+i], " \n"[i==n]);
return 0;
}
【例题】UVA719 Glass Beads
与上一题不同的是,这题要求位置最靠前。
只有一种情况下两道题的答案不一样,那就是字符串恰好为一个循环串的时候。
那么我们换一个写法即可。
const int N = 2e4 + 7;
int n, ans;
char s[N];
inline void solve() {
rds(s, n);
for (int i = 1; i <= n; i++) s[i+n] = s[i];
int i = 1;
while (i <= n) {
ans = i;
int j = i, k = i + 1;
while (k <= n * 2 && s[j] <= s[k]) j = s[j] == s[k++] ? j + 1 : i;
while (i <= j) i += k - j;
}
print(ans);
}
int main() {
int T;
rd(T);
while (T--) solve();
return 0;
}
参考资料
- OI Wiki Lyndon 分解
- wucstdio 题解 P6127 【【模板】Lyndon 分解】