Processing math: 4%
欢迎光临 ~|

Laijinyi

园龄:1年7个月粉丝:2关注:2

P3735 = LOJ 2278 字符串 题解

一句话题解:

  • “相等”等价于 LCP+LCS+klen
  • 对于每个字符串 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,一个 ip[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^5p 最多产生 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 中国大陆许可协议进行许可。

posted @   Laijinyi  阅读(4)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起