专栏文章

题解: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 个月前
查看原文
{SolutionNo.020 AT_arc203_d}× By Xyz105\begin{Bmatrix}\color{red}\LARGE\bold{Solution}\\\normalsize\texttt{No.020 }\bold{AT\_arc203\_d}\end{Bmatrix}\times\footnotesize\texttt{ By Xyz105}

题目描述

给定一串长度为 NN01\texttt{01} 序列 AA。有如下问题:
另有一串 01\texttt{01} 序列 BB(下标从 11 开始编号)。可以对其进行任意次操作,每次选取一个 i[1,B)i\isin [1,|B|),在 BiB_iBi+1B_{i+1} 之间插入 BiBi+1B_i \oplus B_{i+1}
BB 能经过上述操作变换得到 AA 的前提下,求出 B|B| 的最小值。
现有 QQ 次询问。每次询问会反转 AA 的其中一个数,同时要求输出上述问题的答案。3N2×105Q5×1053\le N\le 2\times 10^5,Q\le 5\times 10^5

解题思路

一步一步来。
引理 1
AA 中每个长度为 xx0\texttt{0} 连通块,都只能BB 中对应的长度为 yy0\texttt{0} 连通块变换得到。其中 xy2x\ge y\ge 2
证明显然,掺入任何一个 1\texttt{1} 都不行。
引理 2
形如 1...10\texttt{1...10} 的串,可以只从 10\texttt{10} 开始变换得到。其中“...\texttt{...}”是任意长度的 01\texttt{01} 串(当然可以是空串),且不包括任何长度 2\ge 20\texttt{0} 连通块。
构造方式为,先将 10\texttt{10} 变换成 11.....many ’1’s110\texttt{11}\underbrace{\texttt{.....}}_{\texttt{many '1's}}\texttt{110},使得 1\texttt{1} 的数量符合要求;再在某些 11\texttt{11} 之间插入 0\texttt{0} 即可。
注:对称情况同理。
引理 3
形如 00..0...00..0...(repetitive)00..0\underbrace{\textcolor{red}{\texttt{00..0}}\textcolor{blue}{\texttt{...}}\textcolor{red}{\texttt{00..0}}\textcolor{blue}{\texttt{...}}}_{\texttt{(repetitive)}}\textcolor{red}{\texttt{00..0}} 的串,其最短能从 001001(repetitive)00\underbrace{\texttt{001001}}_{\texttt{(repetitive)}}\texttt{00} 变换得到。
其中标红的 00..0\textcolor{red}{\texttt{00..0}} 是长度 2\ge 20\texttt{0} 连通块,每个连通块相对应地由长度 =2=200\texttt{00} 生成(引理 1)。
标蓝的 ...\textcolor{blue}{\texttt{...}} 是任意长度的 01\texttt{01} 串,且不包括任何长度 2\ge 20\texttt{0} 连通块(并且头尾两端的字符必须是 1\texttt{1})。可由对应的 1\texttt{1} 跟其旁边的 00\texttt{00} 生成(引理 2)。
引理 4
形如 0...00..0\textcolor{green}{\texttt{0}}\textcolor{blue}{\texttt{...}}\textcolor{red}{\texttt{00..0}} 的串,其最短能从 0100\texttt{0100} 变换得到;
形如 1...00..0\textcolor{green}{\texttt{1}}\textcolor{blue}{\texttt{...}}\textcolor{red}{\texttt{00..0}} 的串,其最短能从 100\texttt{100} 变换得到。
其中 00..0\textcolor{red}{\texttt{00..0}}...\textcolor{blue}{\texttt{...}} 意义同 引理 3
注:对称情况同理。
综上所述,我们可以分类讨论出,在没有修改操作的情况下题干所述问题的答案。
  • AA包含长度 2\ge 20\texttt{0} 连通块,则 AA 一定形如 ....00..0...00..0...(repetitive)00..0....\textcolor{green}{\texttt{....}}\underbrace{\textcolor{red}{\texttt{00..0}}\textcolor{blue}{\texttt{...}}\textcolor{red}{\texttt{00..0}}\textcolor{blue}{\texttt{...}}}_{\texttt{(repetitive)}}\textcolor{red}{\texttt{00..0}}\textcolor{green}{\texttt{....}}
    将答案 ans\text{ans} 初值设为 (( 00..0\textcolor{red}{\texttt{00..0}} 的个数 )×31)\times 3-1,也就是去掉头尾两端的“....\textcolor{green}{\texttt{....}}”后对应 001001(repetitive)00\underbrace{\texttt{001001}}_{\texttt{(repetitive)}}\texttt{00} 的长度(引理 3)。
    接着讨论头部的“....\textcolor{green}{\texttt{....}}”对答案的贡献。
    • ....\textcolor{green}{\texttt{....}} 为空串,则对 ans\text{ans} 没有贡献;
    • ....\textcolor{green}{\texttt{....}} 不为空串,则显然要求其末尾字符为 1\texttt{1}
      • 若其开头字符为 0\texttt{0},则对 ans\text{ans} 造成 22 的贡献(引理 4);
      • 若其开头字符为 1\texttt{1},则对 ans\text{ans} 造成 11 的贡献(引理 4)。
    尾部的“....\textcolor{green}{\texttt{....}}”对答案的贡献同理。
  • AA不包含长度 2\ge 20\texttt{0} 连通块,则有:
    • AA 串为全 11 串,则 ans=n\text{ans}=n
    • 反之若 AA 串的开头跟末尾字符均为 0\texttt{0},则 ans=3\text{ans}=3(由 010\texttt{010} 生成);
    • 反之若 AA 串的开头跟末尾字符均为 1\texttt{1},则 ans=2\text{ans}=2(由 11\texttt{11} 生成);
    • 反之则 ans=2\text{ans}=2(由 01\texttt{01}10\texttt{10} 生成)。
    生成构造方式不难想出。
现在要引入修改操作。可以考虑使用线段树,需要维护的信息为(仅供参考):
  • 长度 2\ge 20\texttt{0} 连通块的个数;
  • 长度 2\ge 20\texttt{0} 连通块的 第一次 和 最后一次 出现的位置;
  • 1\texttt{1} 的总个数(方便处理 全 11 串 的情况);
  • 开头 和 末尾 的字符。
到这里就做完了,总码量不算大。

参考代码

赛时吃了一发罚时。 Submission on AtCoder
CPP
#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 条评论,欢迎与作者交流。

正在加载评论...