最小表示法
\(\text{luogu-13270}\)
最小表示板子。
若长度为 \(n\) 的字符串 \(s\) 中可以选择一个位置 \(i\),使得 \(\overline{s_i\cdots s_ns_1\cdots s_{i-1}}=t\),则称 \(s\) 与 \(t\) 循环同构。字符串 \(s\) 的最小表示为与 \(s\) 循环同构的所有字符串中字典序最小的字符串。
给定一个长度为 \(n\) 的字符串 \(s\),请求出 \(s\) 的最小表示。
首先考虑暴力,枚举循环同构串的第一个位置,然后暴力比较,\(O(n^2)\)。
我们可以优化暴力,将字符串先拼一个串到末尾,可以预处理哈希值,然后用二分找到第一个不相等的位置,看是否更新为此位置即可,\(O(n \log n)\)。
考虑接着优化,假设目前要比较 \(mk\) 为开头和 \(i\) 为开头的字符串,首先暴力找到一个 \(r < n\) 使得 \(s_{mk \sim mk + r - 1}\) 与 \(s_{i \sim i + r - 1}\) 相等,\(s_{mk+r}\) 和 \(s_{i+r}\) 不相等。如果没有合适的 \(r\) 说明 \(s\) 中所有字符相等。
如果 \(s_{mk+r}<s_{i+r}\),说明对于所有 \(0 \le k \le r\),以 \(i+k\) 开头的字符串不可能成为最优解,此时直接更新 \(i \gets i+r+1\) 即可。
否则说明 \(s_{i+r}\) 更优,直接更新 \(i \gets \max(i+1,mk+j+1)\) 即可。
时间复杂度证明:
对于 \(s_{mk+r}<s_{i+r}\),通过 \(O(r)\) 的枚举使 \(i\) 前进了 \(r\) 步,最多移动 \(n\) 步,时间复杂度均摊 \(O(n)\)。
对于 \(s_{mk+r}>s_{i+r}\),\(mk\) 和 \(i\) 总共移动了至少 \(r\) 步,最多移动 \(n\) 步,时间复杂度均摊 \(O(n)\)。
所以总时间复杂度为 \(O(n)\)。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long read() {
long long x = 0, f = 1;
char c = getchar();
while(c > 57 || c < 48) { if(c == 45) f = -1; c = getchar(); }
while(c >= 48 && c <= 57) { x = (x << 1) + (x << 3) + (c - 48); c = getchar(); }
return x * f;
}
long long ls;
string s;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> ls >> s; s = " " + s + s;
long long mk = 1;
for(int i = 2; i <= ls; ) {
long long r = 0;
while(r < ls && s[mk + r] == s[i + r]) r ++;
if(r == ls) break;
if(s[mk + r] > s[i + r]) {
long long res = mk;
mk = i, i = max(i + 1ll, res + r + 1);
}
else i += r + 1;
}
for(int i = mk; i <= mk + ls - 1; i ++) cout << s[i];
cout << "\n";
return 0;
}
\(\text{luogu-1368}\)
把最小表示的字符串换成数组了而已,不卡 \(O(n \log n)\)。
不过不想写哈希加二分了,就这样改改交了吧。
\(\text{Necklace}\)
给定两个数字组成的字符串 \(s,t\),先判断两个字符串是否循环同构。
如果不循环同构,则输出 \(\text{No}\),否则先输出 \(\text{Yes}\),第二行输出 \(s\) 的最小表示。
\(1 \le |s| \le 10^6\)。
直接处理一下两个串的最小表示,如果两个串的最小表示相等,则易证两个字符串循环同构。
\(\text{hdu-2609}\)
给定 \(n\) 个字符串,判断有多少个不同的字符串,若两个字符串循环同构则看作相同的字符串。
\(2 \le n \le 10^4\)。
把每个字符串处理出来最小表示,然后用 \(\text{map}\) 计数即可。
本文来自博客园,作者:So_noSlack,转载请注明原文链接:https://www.cnblogs.com/So-noSlack/p/19211713

浙公网安备 33010602011771号