Solution S o l u t i o n
因为
qk=P
q
k
=
P
是一个常数,想到可以阈值。
当
k<S
k
<
S
时,对于每个串可以
O(k2)
O
(
k
2
)
暴力在后缀自动机上跑出现次数。对于一个区间
[l,r]
[
l
,
r
]
,直接计算在这个串上的贡献就好了。时间复杂度应该是
O(qk2logm)=O(Pklogm)
O
(
q
k
2
log
m
)
=
O
(
P
k
log
m
)
的???
当
k>S
k
>
S
时,可以对于这个串的每个前缀都记录下沿着后缀自动机走到的节点和匹配的长度,这样的话只要这个后缀的前缀长度合法就好了,这可以在
parent
p
a
r
e
n
t
树上倍增。时间复杂度可能是
O(qmlogk)=O(Pkmlogn)
O
(
q
m
log
k
)
=
O
(
P
k
m
log
n
)
。。
复杂度一通乱分析
反正的话可能得找一下
S
S
<script type="math/tex" id="MathJax-Element-20">S</script>的值。。。刚开始就T了。。
#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> Pairs;
const int N = 202020;
const int M = 722;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0; int sgn = 0;
for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
if (sgn) x = -x;
}
inline void read(char *s) {
static char c; int len = 0;
for (c = get(); c < 'a' || c > 'z'; c = get());
for (; c >= 'a' && c <= 'z'; c = get()) s[len++] = c;
s[len] = 0;
}
namespace SAM {
int go[N][26];
int par[N], rgt[N], mx[N];
int fa[N][26];
int buc[N], id[N];
int root, last, tcnt;
inline void init(void) {
root = last = tcnt = 1;
}
inline int extend(int c) {
int p = last, np = ++tcnt;
mx[np] = mx[p] + 1; rgt[np] = 1;
for (; p && !go[p][c]; p = par[p]) go[p][c] = np;
if (p) {
int q = go[p][c];
if (mx[q] == mx[p] + 1) {
par[np] = q;
} else {
int nq = ++tcnt;
mx[nq] = mx[p] + 1;
par[nq] = par[q];
par[q] = par[np] = nq;
memcpy(go[nq], go[q], sizeof go[q]);
for (; go[p][c] == q; p = par[p]) go[p][c] = nq;
}
} else {
par[np] = root;
}
return last = np;
}
inline void pre(int fl = 0) {
for (int i = 1; i <= tcnt; i++) ++buc[mx[i]];
for (int i = 1; i <= tcnt; i++) buc[i] += buc[i - 1];
for (int i = tcnt; i; i--) id[buc[mx[i]]--] = i;
for (int i = tcnt; i; i--) rgt[par[id[i]]] += rgt[id[i]];
if (fl) {
for (int i = 1; i <= tcnt; i++) *fa[i] = par[i];
for (int i = 1; i <= 20; i++)
for (int u = 1; u <= tcnt; u++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
}
inline int count0(int &u, int c) {
u = go[u][c]; return rgt[u];
}
inline void match(int &u, int &len, int c) {
while (u && !go[u][c]) {
u = par[u]; len = mx[u];
}
if (u) {
u = go[u][c]; ++len;
} else {
u = root; len = 0;
}
}
inline int count1(int u, int k) {
for (int i = 20; ~i; i--)
if (mx[fa[u][i]] >= k) u = fa[u][i];
return rgt[u];
}
}
int n, m, q, k, S;
char s[N], w[N];
int l[N], r[N], id[N];
namespace work0 {
int ans[M][M];
int x, y;
vector<int> seg[M][M];
inline void solve(void) {
for (int i = 0; i < m; i++) {
read(x); read(y);
seg[x][y].push_back(i);
}
for (int i = 0; i < n; i++) SAM::extend(s[i] - 'a');
SAM::pre();
for (int i = 1; i <= q; i++) {
read(w); read(x); read(y);
ll ans = 0;
for (int i = 0; i < k; i++) {
int u = SAM::root;
for (int j = i; j < k; j++) {
int cnt = SAM::count0(u, w[j] - 'a');
if (u == 0) break;
auto l = lower_bound(seg[i][j].begin(), seg[i][j].end(), x);
auto r = upper_bound(seg[i][j].begin(), seg[i][j].end(), y);
ans += (ll)(r - l) * cnt;
}
}
printf("%lld\n", ans);
}
}
}
namespace work1 {
int x, y;
int pos[N], len[N];
int l[N], r[N];
inline void solve(void) {
for (int i = 0; i < m; i++) {
read(l[i]); read(r[i]);
}
for (int i = 0; i < n; i++) SAM::extend(s[i] - 'a');
SAM::pre(1);
for (int i = 1; i <= q; i++) {
read(w); read(x); read(y);
int u = 1, lent = 0, ans = 0;
for (int j = 0; j < k; j++) {
SAM::match(u, lent, w[j] - 'a');
pos[j] = u; len[j] = lent;
}
for (int j = x; j <= y; j++) {
int lent = r[j] - l[j] + 1;
if (lent > len[r[j]]) continue;
ans += SAM::count1(pos[r[j]], lent);
}
printf("%lld\n", ans);
}
}
}
int main(void) {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
SAM::init();
read(n); read(m); read(q); read(k);
read(s);
S = 555;
if (k < S) work0::solve();
else work1::solve();
return 0;
}