BZOJ 4212 并非题解
这个东西实际上过不了(空间炸了),但是正确性是有的。
做法:这个前缀/后缀匹配的形式容易想到在 trie 上考虑。对
原串,反串各建一个 trie,用 dfs 把有某个前缀的串的集合刻画成区间,那么问题就成了下面这个形式:在线区间查询权值在
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现