P3735 = LOJ 2278 字符串 题解
一句话题解:
- “相等”等价于 LCP+LCS+k≥len
- 对于每个字符串 p,枚举其 LCP 长度,同时确定 LCS 长度,问题变成统计有多少 i,满足 s[i-|\text{LCP}|+1..i]=\text{LCP},s[i+k+1..i+k+|\text{LCS}|]=\text{LCS}。
- 得出解法:对 p 建 ACAM,对其反串建 ACAM,一个 i 对 p[1..j] 有贡献,相当于 s[1..i] 在 p[1..j] 的 fail 树子树中,且 s[i+k+1..n] 的反串在 p[j+k+1..|p|] 的反串的 fail 树子树中,条件形如 f(i)\in[l_1..r_1]\land g(i+k+1)\in[l_2..r_2],二维数点即可。
- 去重:答案 =\text{Ans}(k)-\text{Ans}(k-1)。
记一点代码上的问题:
- |p|\le k 时特判,\text{Ans}(k)=|s|-|p|+1,\text{Ans}(k-1)=0。
- 二维数点时矩形数应该开两倍,因为对于每个 |p| 最多产生 |p|+1 个矩形,2\cdot10^5 个 p 最多产生 4\cdot 10^5 个矩形。
#include <bits/stdc++.h> using namespace std; #define rep(i, j, k) for (int i = (j); i <= (k); ++i) #define reo(i, j, k) for (int i = (j); i >= (k); --i) typedef long long ll; const int N = 2e5 + 10; vector<int> Ppos[N], revPpos[N]; string s, p[N]; int n; int f[N], g[N]; struct ACAM { int tot, ch[N][94], fail[N]; ACAM() { memset(ch, 0, sizeof(ch)); memset(fail, 0, sizeof(fail)); tot = 0; memset(dfn, 0, sizeof(dfn)); memset(sz, 0, sizeof(sz)); tim = 0; rep(i, 0, N - 1) G[i].clear(); } void ins(string & s, int id, int op) { int m = s.length(), p = 0; if (!op) Ppos[id].push_back(0); else revPpos[id].push_back(0); rep(i, 0, m - 1) { int now = s[i] - 33; if (!ch[p][now]) ch[p][now] = ++tot; p = ch[p][now]; ((!op) ? Ppos[id] : revPpos[id]).push_back(p); } if (op) { reverse(revPpos[id].begin(), revPpos[id].end()); revPpos[id].push_back(0); int q = revPpos[id].size(); reo(i, q - 1, 1) { revPpos[id][i] = revPpos[id][i - 1]; } revPpos[id][0] = 0; } } vector<int> G[N]; int tim, dfn[N], sz[N]; void DFS(int u) { dfn[u] = ++tim, sz[u] = 1; for (int v : G[u]) DFS(v), sz[u] += sz[v]; } void Buildfail() { queue<int> q; rep(i, 0, 93) if (ch[0][i]) q.push(ch[0][i]); while (!q.empty()) { int u = q.front(); q.pop(); rep(i, 0, 93) if (ch[u][i]) fail[ch[u][i]] = ch[fail[u]][i], q.push(ch[u][i]); else ch[u][i] = ch[fail[u]][i]; } rep(i, 1, tot) G[fail[i]].push_back(i); DFS(0); } void GetFG(int *a, string & s, int op) { int m = s.length(), p = 0; a[0] = 0; rep(i, 0, m - 1) { int now = s[i] - 33; p = ch[p][now], a[i + 1] = p; } if (op) { reverse(a, a + m + 1); reo(i, m + 1, 1) a[i] = a[i - 1]; a[0] = 0; } } } P, revP; int slen, ans[N]; struct Point { int x, y; } points[N]; struct Matrix { int id, Lx, Rx, Ly, Ry; } mats[N << 1]; int mattot; struct Events { int op, x; int xishu, id, l, r; int y; } eve[N << 2]; int evetot; struct BIT { int len, sum[N]; void init() { memset(sum, 0, sizeof(sum)); len = revP.tot + 2; } void upd(int x, int v) { for (++x; x <= len; x += x & -x) sum[x] += v; } int qry(int x) { int res = 0; for (++x; x; x -= x & -x) res += sum[x]; return res; } int qry(int l, int r) { return qry(r) - qry(l - 1); } } bit; void Solve(int k, int xishu, int op) { rep(i, 0, slen - k) { points[i] = (Point){P.dfn[f[i]], revP.dfn[g[i + k + 1]]}; } mattot = evetot = 0; rep(i, 1, n) { int plen = p[i].length(); if (plen <= k) { if (!op) ans[i] += xishu * (slen - plen + 1); } else { rep(j, op, plen - k - op) { int u = Ppos[i][j], v = revPpos[i][j + k + 1]; mats[++mattot] = (Matrix){i, P.dfn[u], P.dfn[u] + P.sz[u] - 1, revP.dfn[v], revP.dfn[v] + revP.sz[v] - 1}; } } } rep(i, 0, slen - k) { eve[++evetot] = (Events){0, points[i].x, 0, 0, 0, 0, points[i].y}; } rep(i, 1, mattot) { eve[++evetot] = (Events){1, mats[i].Lx - 1, xishu * -1, mats[i].id, mats[i].Ly, mats[i].Ry, 0}; eve[++evetot] = (Events){1, mats[i].Rx, xishu, mats[i].id, mats[i].Ly, mats[i].Ry, 0}; } sort(eve + 1, eve + evetot + 1, [&](Events u, Events v) { return (u.x != v.x) ? (u.x < v.x) : (u.op < v.op); }); bit.init(); rep(i, 1, evetot) { int op = eve[i].op; if (!op) { bit.upd(eve[i].y, 1); } else { ans[eve[i].id] += eve[i].xishu * bit.qry(eve[i].l, eve[i].r); } } } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int k; cin >> k >> s >> n, slen = s.length(); int sum = 0; rep(i, 1, n) { cin >> p[i], P.ins(p[i], i, 0), sum += p[i].length(); string t = p[i]; reverse(t.begin(), t.end()), revP.ins(t, i, 1); } P.Buildfail(), revP.Buildfail(); P.GetFG(f, s, 0); string t = s; reverse(t.begin(), t.end()); revP.GetFG(g, t, 1); Solve(k, 1, 0); Solve(k - 1, -1, 1); rep(i, 1, n) cout << ans[i] << '\n'; return 0; }
本文作者:Laijinyi
本文链接:https://www.cnblogs.com/laijinyi/p/18403848
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。