YC302A [ 20240617 CQYC省选模拟赛 T1 ] 构造字符串(string)
题意#
你需要构造一个长度为 的字符串。
使得后缀数组为给定的序列 , 的回文序列为 。
Sol#
注意到后缀数组实际上是一系列 的限制,而 是一堆相等以及两个不相等的限制。
若直接建边很难搞。
考虑将限制统一,后缀数组不好动,可以考虑将 的限制当成 做。
平凡的,按照后缀数组的字典序一位一位确定。
思考 什么时候不能与字典序的前一个 取等。
显然,设 ,则比较 与 的字典序大小。
乍一看我们无法确定 与 的字典序。
但是这个东西不显然等价于 与 在后缀数组的排名大小吗?
剩下地,对于 提供的不等限制,直接扔进桶里,每次清空即可。
不难发现,如果我们尽量放相同的,正好满足了 的限制。
最后直接用 跑一遍,判掉不合法情况即可。
Code#
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现