专栏文章
题解:P3279 [SCOI2013] 密码
P3279题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minlnbsw
- 此快照首次捕获于
- 2025/12/02 04:26 3 个月前
- 此快照最后确认于
- 2025/12/02 04:26 3 个月前
我不会 Manacher,所以我用暴力数据结构过了这道题。
我们发现这个回文的限制和 P3295 [SCOI2016] 萌萌哒 很像。我们直接把那道题的 ST 表并查集搬过来就做完了。
具体来说我们在原串后面拼一个翻转的原串,原串一部分回文就等价于原串的这部分和反转后的这部分相等。
时间复杂度 ,因为有 ST 表所以比普通做法多一个 。ST 表空间带个 ,小心 MLE。
代码比较丑。
CPP#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
const int LOGN = 17;
struct DSU {
int fa[MAXN], siz[MAXN], mn[MAXN];
void init(int n) {
rep(u, 1, n)
fa[u] = u, siz[u] = 1, mn[u] = u;
}
int find(int u) {
return fa[u] == u ? u : (fa[u] = find(fa[u]));
}
void merge(int u, int v) {
u = find(u), v = find(v);
if (u == v)
return;
if (siz[u] > siz[v])
swap(u, v);
fa[u] = v;
siz[v] += siz[u];
mn[v] = min(mn[v], mn[u]);
}
int query_min(int u) {
return mn[find(u)];
}
};
int n;
DSU dsu[LOGN + 1];
void merge(int l1, int r1, int l2, int r2) {
int len = r1 - l1 + 1;
int i = __lg(len);
dsu[i].merge(l1, l2);
dsu[i].merge(r1 - (1 << i) + 1, r2 - (1 << i) + 1);
}
int flip(int x) {
return 2 * n + 1 - x;
}
char ans[MAXN];
int r1[MAXN], r2[MAXN];
vector<int> G[MAXN];
void add_edge(int u, int v) {
if (1 <= u && u <= n && 1 <= v && v <= n) {
u = dsu[0].find(u), v = dsu[0].find(v);
G[u].push_back(v);
G[v].push_back(u);
}
}
char mex(set<char> &st) {
for (char c = 'a'; c <= 'z'; c++)
if (!st.count(c))
return c;
return '#';
}
int main() { ios::sync_with_stdio(0); cin.tie(0);
cin >> n;
rep(i, 0, LOGN)
dsu[i].init(n * 2);
rep(i, 1, n) {
int r; cin >> r; r = (r + 1) / 2;
merge(i-r+1, i, flip(i+r-1), flip(i));
r1[i] = r;
}
rep(i, 1, n-1) {
int r; cin >> r; r = r / 2;
if (r != 0)
merge(i-r+1, i, flip(i+r), flip(i+1));
r2[i] = r;
}
per(i, LOGN, 1) {
rep(u, 1, n * 2 - (1 << i) + 1) {
int v = dsu[i].find(u);
if (u != v) {
dsu[i-1].merge(u, v);
dsu[i-1].merge(u + (1 << (i-1)), v + (1 << (i-1)));
}
}
}
rep(i, 1, n) {
int r = r1[i];
add_edge(i-r, i+r);
}
rep(i, 1, n-1) {
int r = r2[i];
add_edge(i-r, i+r+1);
}
set<char> st[MAXN];
rep(i, 1, n) {
int u = dsu[0].query_min(i);
if (i == u) {
int rt = dsu[0].find(i);
ans[i] = mex(st[rt]);
for (auto v : G[rt])
st[v].insert(ans[i]);
} else
ans[i] = ans[u];
cout << ans[i];
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...