目录
马拉车(Manacher)
/** 马拉车(Manacher, with string)
* 2024-04-06: https://qoj.ac/submission/380047
* 2024-04-09: https://qoj.ac/submission/384389 【模板】
**/
std::vector<int> manacher(std::string s) {
std::string t = "#";
for (auto c : s) {
t += c;
t += '#';
}
int n = t.size();
std::vector<int> r(n);
for (int i = 0, j = 0; i < n; i++) {
if (2 * j - i >= 0 && j + r[j] > i) {
r[i] = std::min(r[2 * j - i], j + r[j] - i);
}
while (i - r[i] >= 0 && i + r[i] < n && t[i - r[i]] == t[i + r[i]]) {
r[i] += 1;
}
if (i + r[i] > j + r[j]) {
j = i;
}
}
return r;
}
Z 函数
/** Z函数
* 2023-08-11: https://ac.nowcoder.com/acm/contest/view-submission?submissionId=63378373
* 2024-04-09: https://qoj.ac/submission/384405 【模板】
**/
std::vector<int> Z(std::string s) {
int n = s.size();
std::vector<int> z(n + 1);
z[0] = n;
for (int i = 1, j = 1; i < n; i++) {
z[i] = std::max(0, std::min(j + z[j] - i, z[i - j]));
while (i + z[i] < n && s[z[i]] == s[i + z[i]]) {
z[i]++;
}
if (i + z[i] > j + z[j]) {
j = i;
}
}
return z;
}
后缀数组
/** 后缀数组(SuffixArray 旧版)
* 2023-03-14: https://atcoder.jp/contests/discovery2016-qual/submissions/39727257
* 2023-09-05: https://qoj.ac/submission/164483
* 2024-04-09: https://qoj.ac/submission/384415 【模板】
**/
struct SuffixArray {
int n;
std::vector<int> sa, rk, lc;
SuffixArray(const std::string &s) {
n = s.length();
sa.resize(n);
lc.resize(n - 1);
rk.resize(n);
std::iota(sa.begin(), sa.end(), 0);
std::sort(sa.begin(), sa.end(), [&](int a, int b) {return s[a] < s[b];});
rk[sa[0]] = 0;
for (int i = 1; i < n; ++i)
rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]);
int k = 1;
std::vector<int> tmp, cnt(n);
tmp.reserve(n);
while (rk[sa[n - 1]] < n - 1) {
tmp.clear();
for (int i = 0; i < k; ++i)
tmp.push_back(n - k + i);
for (auto i : sa)
if (i >= k)
tmp.push_back(i - k);
std::fill(cnt.begin(), cnt.end(), 0);
for (int i = 0; i < n; ++i)
++cnt[rk[i]];
for (int i = 1; i < n; ++i)
cnt[i] += cnt[i - 1];
for (int i = n - 1; i >= 0; --i)
sa[--cnt[rk[tmp[i]]]] = tmp[i];
std::swap(rk, tmp);
rk[sa[0]] = 0;
for (int i = 1; i < n; ++i)
rk[sa[i]] = rk[sa[i - 1]] + (tmp[sa[i - 1]] < tmp[sa[i]] || sa[i - 1] + k == n || tmp[sa[i - 1] + k] < tmp[sa[i] + k]);
k *= 2;
}
for (int i = 0, j = 0; i < n; ++i) {
if (rk[i] == 0) {
j = 0;
} else {
for (j -= j > 0; i + j < n && sa[rk[i] - 1] + j < n && s[i + j] == s[sa[rk[i] - 1] + j]; )
++j;
lc[rk[i] - 1] = j;
}
}
}
};
后缀自动机(SAM 新版)
/** 后缀自动机(SAM 新版)
* 2023-05-27: https://cf.dianhsu.com/gym/104353/submission/207318083
* 2023-09-25: https://qoj.ac/submission/188106
* 2024-04-09: https://qoj.ac/submission/384423 【模板】
* 2024-04-09: https://qoj.ac/submission/384429 【模板】
**/
struct SAM {
static constexpr int ALPHABET_SIZE = 26;
struct Node {
int len;
int link;
std::array<int, ALPHABET_SIZE> next;
Node() : len{}, link{}, next{} {}
};
std::vector<Node> t;
SAM() {
init();
}
void init() {
t.assign(2, Node());
t[0].next.fill(1);
t[0].len = -1;
}
int newNode() {
t.emplace_back();
return t.size() - 1;
}
int extend(int p, int c) {
if (t[p].next[c]) {
int q = t[p].next[c];
if (t[q].len == t[p].len + 1) {
return q;
}
int r = newNode();
t[r].len = t[p].len + 1;
t[r].link = t[q].link;
t[r].next = t[q].next;
t[q].link = r;
while (t[p].next[c] == q) {
t[p].next[c] = r;
p = t[p].link;
}
return r;
}
int cur = newNode();
t[cur].len = t[p].len + 1;
while (!t[p].next[c]) {
t[p].next[c] = cur;
p = t[p].link;
}
t[cur].link = extend(p, c);
return cur;
}
int extend(int p, char c, char offset = 'a') {
return extend(p, c - offset);
}
int next(int p, int x) {
return t[p].next[x];
}
int next(int p, char c, char offset = 'a') {
return next(p, c - 'a');
}
int link(int p) {
return t[p].link;
}
int len(int p) {
return t[p].len;
}
int size() {
return t.size();
}
};
KMP
/** 前缀函数(KMP)
* 2023-11-17: https://qoj.ac/submission/253754
* 2024-04-09: https://qoj.ac/submission/384408 【模板】
**/
std::vector<int> kmp(std::string s) {
int n = s.size();
std::vector<int> f(n + 1);
for (int i = 1, j = 0; i < n; i++) {
while (j && s[i] != s[j]) {
j = f[j];
}
j += (s[i] == s[j]);
f[i + 1] = j;
}
return f;
}
字符串哈希
// 2022-06-09 13:19:32
// https://codeforces.com/contest/1598/submission/160006998
#include <bits/stdc++.h>
using i64 = long long;
bool isprime(int n) {
if (n <= 1) {
return false;
}
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
int findPrime(int n) {
while (!isprime(n)) {
n++;
}
return n;
}
using Hash = std::array<int, 2>;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
const int P = findPrime(rng() % 900000000 + 100000000);
std::string s, x;
std::cin >> s >> x;
int n = s.length();
int m = x.length();
std::vector<int> h(n + 1), p(n + 1);
for (int i = 0; i < n; i++) {
h[i + 1] = (10LL * h[i] + s[i] - '0') % P;
}
p[0] = 1;
for (int i = 0; i < n; i++) {
p[i + 1] = 10LL * p[i] % P;
}
auto get = [&](int l, int r) {
return (h[r] + 1LL * (P - h[l]) * p[r - l]) % P;
};
int px = 0;
for (auto c : x) {
px = (10LL * px + c - '0') % P;
}
for (int i = 0; i <= n - 2 * (m - 1); i++) {
if ((get(i, i + m - 1) + get(i + m - 1, i + 2 * m - 2)) % P == px) {
std::cout << i + 1 << " " << i + m - 1 << "\n";
std::cout << i + m << " " << i + 2 * m - 2 << "\n";
return 0;
}
}
std::vector<int> z(m + 1), f(n + 1);
z[0] = m;
for (int i = 1, j = -1; i < m; i++) {
if (j != -1) {
z[i] = std::max(0, std::min(j + z[j] - i, z[i - j]));
}
while (z[i] + i < m && x[z[i]] == x[z[i] + i]) {
z[i]++;
}
if (j == -1 || i + z[i] > j + z[j]) {
j = i;
}
}
for (int i = 0, j = -1; i < n; i++) {
if (j != -1) {
f[i] = std::max(0, std::min(j + f[j] - i, z[i - j]));
}
while (f[i] + i < n && f[i] < m && x[f[i]] == s[f[i] + i]) {
f[i]++;
}
if (j == -1 || i + f[i] > j + f[j]) {
j = i;
}
}
for (int i = 0; i + m <= n; i++) {
int l = std::min(m, f[i]);
for (auto j : { m - l, m - l - 1 }) {
if (j <= 0) {
continue;
}
if (j <= i && (get(i - j, i) + get(i, i + m)) % P == px) {
std::cout << i - j + 1 << " " << i << "\n";
std::cout << i + 1 << " " << i + m << "\n";
return 0;
}
if (i + m + j <= n && (get(i, i + m) + get(i + m, i + m + j)) % P == px) {
std::cout << i + 1 << " " << i + m << "\n";
std::cout << i + m + 1 << " " << i + m + j << "\n";
return 0;
}
}
}
return 0;
}