专栏文章
题解:AT_arc203_d [ARC203D] Insert XOR
AT_arc203_d题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miojcmpd
- 此快照首次捕获于
- 2025/12/02 20:09 3 个月前
- 此快照最后确认于
- 2025/12/02 20:09 3 个月前
题目描述
给定一串长度为 的 序列 。有如下问题:
另有一串 序列 (下标从 开始编号)。可以对其进行任意次操作,每次选取一个 ,在 和 之间插入 。
在 能经过上述操作变换得到 的前提下,求出 的最小值。
现有 次询问。每次询问会反转 的其中一个数,同时要求输出上述问题的答案。。
解题思路
一步一步来。
引理 1中每个长度为 的 连通块,都只能由 中对应的长度为 的 连通块变换得到。其中 。证明显然,掺入任何一个 都不行。
引理 2形如 的串,可以只从 开始变换得到。其中“”是任意长度的 串(当然可以是空串),且不包括任何长度 的 连通块。构造方式为,先将 变换成 ,使得 的数量符合要求;再在某些 之间插入 即可。注:对称情况同理。
引理 3形如 的串,其最短能从 变换得到。
其中标红的 是长度 的 连通块,每个连通块相对应地由长度 的 生成(引理 1)。
标蓝的 是任意长度的 串,且不包括任何长度 的 连通块(并且头尾两端的字符必须是 )。可由对应的 跟其旁边的 生成(引理 2)。
引理 4形如 的串,其最短能从 变换得到;
形如 的串,其最短能从 变换得到。
其中 和 意义同 引理 3。注:对称情况同理。
综上所述,我们可以分类讨论出,在没有修改操作的情况下题干所述问题的答案。
-
若 串包含长度 的 连通块,则 一定形如 。
将答案 初值设为 的个数 ,也就是去掉头尾两端的“”后对应 的长度(引理 3)。
接着讨论头部的“”对答案的贡献。- 若 为空串,则对 没有贡献;
- 若 不为空串,则显然要求其末尾字符为 。
- 若其开头字符为 ,则对 造成 的贡献(引理 4);
- 若其开头字符为 ,则对 造成 的贡献(引理 4)。
尾部的“”对答案的贡献同理。 -
若 串不包含长度 的 连通块,则有:
- 若 串为全 串,则 ;
- 反之若 串的开头跟末尾字符均为 ,则 (由 生成);
- 反之若 串的开头跟末尾字符均为 ,则 (由 生成);
- 反之则 (由 或 生成)。
生成构造方式不难想出。
现在要引入修改操作。可以考虑使用线段树,需要维护的信息为(仅供参考):
- 长度 的 连通块的个数;
- 长度 的 连通块的 第一次 和 最后一次 出现的位置;
- 的总个数(方便处理 全 串 的情况);
- 开头 和 末尾 的字符。
到这里就做完了,总码量不算大。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 10, INF = 0x3f3f3f3f;
int n, q, a[MAXN];
#define left (u << 1)
#define right ((u << 1) | 1)
struct node{
int res, posl = INF, posr = -INF, cnt1 = 0;
bool pre, lst;
}t[MAXN << 2];
inline void push_up(node &u, node &lch, node &rch, int l, int r)
{
int mid = (l + r) >> 1;
u.cnt1 = lch.cnt1 + rch.cnt1;
u.pre = lch.pre, u.lst = rch.lst;
u.posl = min(lch.posl, rch.posl), u.posr = max(lch.posr, rch.posr);
(!lch.lst && !rch.pre) && (u.posl = min(u.posl, mid), u.posr = max(u.posr, mid + 1));
if (lch.posr == mid && rch.posl == mid + 1)
u.res = lch.res + rch.res - 1;
else if (lch.posr != mid && rch.posl == mid + 1)
u.res = lch.res + rch.res;
else if (lch.posr == mid && rch.posl != mid + 1)
u.res = lch.res + rch.res;
else if (lch.posr != mid && rch.posl != mid + 1)
u.res = lch.res + rch.res + (!lch.lst && !rch.pre);
}
inline void build(int u = 1, int l = 1, int r = n)
{
if (l == r)
return
t[u].pre = t[u].lst = t[u].cnt1 = a[l],
t[u].posl = INF, t[u].posr = -INF,
t[u].res = 0, void();
int mid = (l + r) >> 1;
build(left, l, mid), build(right, mid + 1, r);
push_up(t[u], t[left], t[right], l, r);
}
inline void change(int pos, int u = 1, int l = 1, int r = n)
{
if (l == r)
return t[u].lst = t[u].cnt1 = (t[u].pre ^= 1), void();
int mid = (l + r) >> 1;
if (pos <= mid) change(pos, left, l, mid);
else change(pos, right, mid + 1, r);
push_up(t[u], t[left], t[right], l, r);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
build();
scanf("%d", &q); int x;
while (q--)
{
scanf("%d", &x), change(x);
if (t[1].cnt1 == n) printf("%d\n", n);
else if (t[1].cnt1 == 0) printf("%d\n", 2);
else if (t[1].res)
{
int ans = t[1].res * 3 - 1;
if (t[1].posl != 1) ans += 1 + (!t[1].pre);
if (t[1].posr != n) ans += 1 + (!t[1].lst);
printf("%d\n", ans);
}
else printf("%d\n", 2 + (!t[1].pre && !t[1].lst));
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...