BZOJ 4212 并非题解

ref

这个东西实际上过不了(空间炸了),但是正确性是有的。

做法:这个前缀/后缀匹配的形式容易想到在 trie 上考虑。对
原串,反串各建一个 trie,用 dfs 把有某个前缀的串的集合刻画成区间,那么问题就成了下面这个形式:在线区间查询权值在 [x,y] 中的数的个数。主席树维护一下。

const int N = 2e3 + 10, L = 2e6 + 10;
bool st;
namespace trie {
int w[L][26], sufw[L][26];
int sz[L], dfn[L], R[L];
int sufsz[L], sufdfn[L], sufR[L];
int tot, dfntot, suftot, sufdfntot;
void insert(const string& s) {
int u = 0;
for (auto c : s) {
if (!w[u][c - 'a']) {
w[u][c - 'a'] = ++tot;
}
u = w[u][c - 'a'];
}
sz[u]++;
}
void sufins(const string& s) {
int u = 0;
for (auto c : s) {
if (!sufw[u][c - 'a']) {
sufw[u][c - 'a'] = ++suftot;
}
u = sufw[u][c - 'a'];
}
sufsz[u]++;
}
void dfs(int u) {
dfn[u] = ++dfntot;
fir (i, 0, 26) {
if (w[u][i]) {
dfs(w[u][i]); sz[u] += sz[w[u][i]];
}
}
R[u] = dfntot;
}
void sufdfs(int u) {
sufdfn[u] = ++sufdfntot;
fir (i, 0, 26) {
if (sufw[u][i]) {
sufdfs(sufw[u][i]); sufsz[u] += sufsz[sufw[u][i]];
}
}
sufR[u] = sufdfntot;
}
int find(const string& s) {
int u = 0;
for (auto c : s) {
if (w[u][c - 'a']) {
u = w[u][c - 'a'];
} else return -1;
}
return u;
}
int suffind(const string& s) {
int u = 0;
for (auto c : s) {
if (sufw[u][c - 'a']) {
u = sufw[u][c - 'a'];
} else return -1;
}
return u;
}
}
namespace seg {
int w[L << 5], rt[L], ls[L << 5], rs[L << 5], tot;
#define mid ((l + r) >> 1)
void pushup(int u) {
w[u] = w[ls[u]] + w[rs[u]];
}
void ins(int& u, int lst, int l, int r, int pos) {
u = ++tot;
w[u] = w[lst];
if (l == r) {
w[u]++; return;
}
if (pos <= mid) ins(ls[u], ls[lst], l, mid, pos), rs[u] = rs[lst];
else ins(rs[u], rs[lst], mid + 1, r, pos), ls[u] = ls[lst];
pushup(u);
}
int query(int u, int lst, int l, int r, int ql, int qr) {
if (!u) return 0;
if (ql <= l and r <= qr) return w[u] - w[lst];
if (qr < l or r < ql) return 0;
return query(ls[u], ls[lst], l, mid, ql, qr) + query(rs[u], rs[lst], mid + 1, r, ql, qr);
}
}
using seg::rt;
bool ed;
int main() {
#ifdef LOCAL
assert(freopen("1.in", "r", stdin));
assert(freopen("test.out", "w", stdout));
assert(freopen("test.err", "w", stderr));
#endif
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
vla<string> s(n + 1), rs(n + 1);
F (i, 1, n) {
cin >> s[i];
trie::insert(s[i]);
rs[i] = s[i]; std::reverse(all(rs[i]));
trie::sufins(rs[i]);
}
trie::sufdfs(0);
trie::dfs(0);
vi a(trie::dfntot + 1);
F (i, 1, n) {
int u = trie::suffind(rs[i]), t = trie::dfn[trie::find(s[i])];
a[t] = trie::sufdfn[u];
}
F (i, 1, trie::dfntot) {
seg::ins(rt[i], rt[i - 1], 1, trie::dfntot, a[i]);
}
int Q; cin >> Q;
int lst = 0;
F (i, 1, Q) {
string s1, s2; cin >> s1 >> s2;
for (auto& c : s1) {
c = (c - 'a' + lst) % 26 + 'a';
}
for (auto& c : s2) {
c = (c - 'a' + lst) % 26 + 'a';
}
std::reverse(all(s2));
int x = trie::find(s1), y = trie::suffind(s2);
if (x == -1 or y == -1) {
cout << "0\n"; continue;
}
debug(i, x, y);
int L = trie::dfn[x], R = trie::R[x];
int lo = trie::sufdfn[y], up = trie::sufR[y];
debug(L, R, lo, up);
cout << (lst = seg::query(rt[R], rt[L - 1], 1, trie::dfntot, lo, up)) << "\n";
lst %= 26;
}
return 0;
}
posted @   rhineofts  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示