YC302A [ 20240617 CQYC省选模拟赛 T1 ] 构造字符串(string)

cxqghzj·2024-06-17 18:18·11 次阅读

YC302A [ 20240617 CQYC省选模拟赛 T1 ] 构造字符串(string)

题意#

你需要构造一个长度为 n 的字符串。

使得后缀数组为给定的序列 amanacher 的回文序列为 b

Sol#

注意到后缀数组实际上是一系列 的限制,而 manacher 是一堆相等以及两个不相等的限制。

若直接建边很难搞。

考虑将限制统一,后缀数组不好动,可以考虑将 manacher 的限制当成 做。

平凡的,按照后缀数组的字典序一位一位确定。

思考 j 什么时候不能与字典序的前一个 i 取等。

Si,Si+1,...Sn

Sj,Sj+1,...Sn

显然,设 Si=Sj,则比较 Si+1,...SnSj+1,..Sn 的字典序大小。

乍一看我们无法确定 Si+1Sj+1 的字典序。

但是这个东西不显然等价于 i+1j+1 在后缀数组的排名大小吗?

剩下地,对于 manacher 提供的不等限制,直接扔进桶里,每次清空即可。

不难发现,如果我们尽量放相同的,正好满足了 manacher 的限制。

最后直接用 manacher 跑一遍,判掉不合法情况即可。

Code#

Copy
#include <iostream> #include <algorithm> #include <cstdio> #include <array> #include <queue> #include <vector> #include <bitset> #include <assert.h> using namespace std; #ifdef ONLINE_JUDGE #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; #endif int read() { int p = 0, flg = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') flg = -1; c = getchar(); } while (c >= '0' && c <= '9') { p = p * 10 + c - '0'; c = getchar(); } return p * flg; } void write(int x) { if (x < 0) { x = -x; putchar('-'); } if (x > 9) { write(x / 10); } putchar(x % 10 + '0'); } bool _stmer; const int N = 2e6 + 5; array <vector <int>, N> isl; array <int, N> s, p, h; bitset <N> vis; queue <int> q; void clear() { while (!q.empty()) vis[q.front()] = 0, q.pop(); } array <int, N> arc; void solve() { int n = read(); for (int i = 1; i <= n; i++) { s[i] = read() + 1; p[s[i]] = i, isl[i].clear(); } arc.fill(0); for (int i = 1; i <= 2 * n - 1; i++) { h[i] = read(); int len = h[i] / 2; if (i & 1) { int tp1 = (i + 1) / 2 - len - 1, tp2 = (i + 2) / 2 + len + 1; if (tp1 < 1 || tp2 > n) continue; isl[tp1].push_back(tp2), isl[tp2].push_back(tp1); } else { int tp1 = (i / 2) - len, tp2 = (i / 2) + len + 1; if (tp1 < 1 || tp2 > n) continue; isl[tp1].push_back(tp2), isl[tp2].push_back(tp1); } } p[n + 1] = 0; int res = 'a'; string ans(n, ' '); clear(); for (int i = 1; i <= n; i++) { if (i != 1 && (vis[s[i]] || p[s[i] + 1] < p[s[i - 1] + 1])) clear(), res++; if (res > 'z') return (void)puts("-1"); ans[s[i] - 1] = res; for (auto k : isl[s[i]]) vis[k] = 1, q.push(k); } string tp; tp.push_back('~'); for (auto k : ans) tp.push_back('|'), tp.push_back(k); tp.push_back('|'); int mid = 0, r = 0; for (int i = 1; i <= 2 * n; i++) { if (i <= r) arc[i] = min(r - i + 1, arc[2 * mid - i]); while (tp[i - arc[i]] == tp[i + arc[i]]) arc[i]++, assert(i - arc[i] >= 0); if (i + arc[i] > r) r = arc[i] + i - 1, mid = i; if (i != 1 && arc[i] != h[i - 1] + 1) return (void)puts("-1"); } printf("%s\n", ans.c_str()); } bool _edmer; int main() { cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n"; #ifndef cxqghzj /* freopen("string.in", "r", stdin); */ /* freopen("string.out", "w", stdout); */ #endif int T = read(); while (T--) solve(); return 0; }
posted @   cxqghzj  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
目录