【题解】hihocoder - 1465 后缀自动机五·重复旋律8

题目

http://hihocoder.com/problemset/problem/1465

题意

询问某个串 \(T\) 在串 \(S\) 中能与多少子串(可重复)循环匹配(移位后一致)。

题解

  • 题目中的提示已经很详细了,这里稍作补充。
  • 循环移位可以通过将串复制一份来解决,但会带来一些需要解决的问题。
  • 匹配的长度恰好为 \(n(|T|=n)\) 的时候,才能够计数,而且同一个状态只能计一次。
  • 如果当前匹配的长度超过 \(n\) 了,那么就要舍弃掉一些已匹配部分开头的字符,这时候就要通过 \(fa\) 指针向上转移了,直到当前状态的字符串长度区间包括 \(n\)。(也就是用滑动窗口将匹配长度控制在 \(n\)。)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)
#ifdef zerol
#define dbg(args...) do { cout << "\033[32;1m" << #args << " -> "; err(args); } while (0)
#else
#define dbg(...)
#endif
void err() { cout << "\033[39;0m" << endl; }
template<template<typename...> class T, typename t, typename... Args>
void err(T<t> a, Args... args) { for (auto x: a) cout << x << ' '; err(args...); }
template<typename T, typename... Args>
void err(T a, Args... args) { cout << a << ' '; err(args...); }
// -----------------------------------------------------------------------------
const int maxn = 2E5 + 100;

namespace SAM {
const int M = maxn << 1;
int t[M][26], len[M] = {-1}, fa[M], sz = 2, last = 1, cnt[M];
void ins(int ch) {
int p = last, np = last = sz++;
len[np] = len[p] + 1; cnt[np] = 1;
for (; p && !t[p][ch]; p = fa[p])
t[p][ch] = np;
if (!p) { fa[np] = 1; return; }
int q = t[p][ch];
if (len[p] + 1 == len[q]) fa[np] = q;
else {
int nq = sz++; len[nq] = len[p] + 1;
memcpy(t[nq], t[q], sizeof t[0]);
fa[nq] = fa[q];
fa[np] = fa[q] = nq;
for (; t[p][ch] == q; p = fa[p])
t[p][ch] = nq;
}
}

int c[maxn] = {1}, a[M];
void rsort() {
FOR (i, 1, sz) c[len[i]]++;
FOR (i, 1, maxn) c[i] += c[i - 1];
FOR (i, 1, sz) a[--c[len[i]]] = i;
FORD (i, sz - 1, 0) cnt[fa[a[i]]] += cnt[a[i]];
}

bool vis[M];
int go(char* s) {
memset(vis, 0, sizeof vis);
int u = 1, l = 0, n = strlen(s), ret = 0;
FOR (i, 0, 2 * strlen(s) - 1) {
int c = s[i % n] - 'a';
while (u && !t[u][c]) {
u = fa[u];
l = len[u];
}
if (!u) { u = 1; l = 0; continue; }
u = t[u][c];
l++;
while (len[fa[u]] >= n) {
u = fa[u];
l = len[u];
}
if (l >= n && !vis[u]) {
vis[u] = true;
ret += cnt[u];
}
}
return ret;
}
}

using namespace SAM;

char s[maxn];
int main() {
scanf("%s", s);
FOR (i, 0, strlen(s)) ins(s[i] - 'a');
rsort();
int T; cin >> T;
while (T--) {
scanf("%s", s);
cout << go(s) << endl;
}
}