JOISC 2019 简要题解

于 2022.11.19 重修复习,加油!

「JOISC 2019 Day1」考试

  • 给定 \(n\) 个二元组 \((a_i,b_i)\)
  • \(q\) 次询问,每次给定 \(A,B,C\),求 \(a_i\geq A,b_i\geq B,a_i+b_i\geq C\) 的二元组个数。
  • \(n,q\leq 10^5\)

三维偏序模板。

「JOISC 2019 Day1」聚会

  • 交互题,用 \(4\times 10^4\) 次询问确定 \(2000\) 个节点的树。
  • 每次可以询问三个不同的节点 \((x,y,z)\),回答到它们距离和最小的节点编号。

好题,sigongzi 有严格的虚树做法,没太看懂咕咕咕。

这种确定图的形态的交互大抵有一种通法,就是维护当前连通块, 每次尝试扩展。

在树上,往往可以扩展出一条链。

另一个常见技巧,仅仅询问一次的信息量往往太小,不妨直接问遍整个集合。

具体的,实现 \(\text{solve}(\text{root},S)\),表示当前树根和 未确定连边但一定在该子树中的节点集合。

即一开始调用 \(\text{solve}(0,\{1,2,\cdots,n-1\})\)。(题目中树的节点编号为 \(0\sim n-1\)

每次随机找一个点 \(x\),作为这一次的分治中心,然后问遍 \((\text{root},x,i),i\in S,i\neq x\)

现在需要确定的是 \(\text{root}\)\(x\) 的一条链,以及非链节点在谁的子树内,然后递归求解。

那就分类讨论,设 \(o=\text{Query}(\text{root},x,i)\),则:

  • \(o=i\),说明 \(i\)\((\text{root},x)\) 这条链上,放入链集合中。
  • \(o\neq i\),则 \(i\) 一定在点 \(o\) 的子树中,且点 \(o\) 一定在 \((\text{root,x})\) 这条链上,特别的,可能有 \(o=\text{root}\)

这些都基于一个简单性质(好像是某个省选题),

就是 \(o=\text{Query}(x,y,z)\),那么 \(o\) 就是 \(x,y,z\) 两两 \(\text{lca}\) 中,最深的节点,且无论树根是谁,一定唯一确定。

那么若点在链上,就一定有 \(o=i\),否则 \(o\) 一定是 \(i\) 不断跳 \(\text{fa}\) 跳到的第一个链节点。

这里可以卡个常,就是如果之前有过 \(o\neq i\),那么 \(o\) 可以不用询问,但是应该没啥必要。

然后确定链的连边需要对链排序,显然就是 \(\text{Query}(\text{root},x,y)=x\) 的话 \(x\) 就更浅。

这里没必要再写个随机化,实际就是快排的过程,直接用 sort 就行。

这样随机分治的复杂度大概是对的,虽然有度数保证但是也不知道咋估计。

可以确定的是,每次分治能够取到重心是最优的,就像点分治的过程。(是否代表了随机点分治的正确性)

「JOISC 2019 Day1」馕

  • 一个长度为 \(L\) 的馕被分为 \(L\) 段,每段一个单位长度,分别表示一种口味。
  • \(n\) 个人,用 \(v_{i,j}\) 表示第 \(i\in[1,n]\) 个人每吃一个单位长度的 \(j\in[1,L]\) 口味的馕获得的愉悦值。
  • 现需要构造一个顺序,并给每个人划分一段馕,按顺序从头开始每个人获得一定的长度(可以是分数)。
  • 要求每个人获得的愉悦值 \(\geq (\sum v_i)/n\),即自己独吞这个馕的愉悦值 \(\frac{1}{n}\)。或者输出无解。
  • \(n,m\leq 2000,v_{i,j}\leq 10^5\)

很神奇的构造题,最后一句就很灵性,因为事实证明不会出现无解情况。

考虑预处理每个人的愉悦值平均分为 \(n\) 段的划分,每次他分到的一定不能被某段严格包含。

但这样就分为包含一段和横跨两段的情况,实际上可以直接选择前者构造。

每次,选择第 \(i\) 段划分右端点最小的人划分真正的第 \(i\) 段,这样的好处是,第 \(i+1\) 个人的第 \(i\) 段一定有的多!

这么划分下来,就直接符合要求了!就是这么神奇。

「JOISC 2019 Day2」两个天线

  • 给定一排 \(n\) 个点,每个点三个参数 \(h_i,a_i,b_i\),它能和 \(|i-j|\in [a_i,b_i]\)\(j\) 建立 \(i\to j\) 的联系。
  • 每对能够双向联系的点能够贡献权值 \(|h_i-h_j|\)
  • \(q\) 次询问,子区间 \([l,r]\) 中的最大权值。
  • \(n,q\leq 2\times 10^5\)

被称为憨批数据结构题,但是感觉这个线段树有点妙。

先拆绝对值,分是否将 \(h_i\) 取反做两遍即可强制规定是 \(i<j,h_j-h_i\)

只考虑后对前的贡献,即对于 \(i<j\),在点 \(i\) 处维护答案,直接扫描一遍用线段树维护。

具体的,每个节点维护两个权值 \((x,y)\),意义之后讨论。

对于每个节点,在 \([i+a_i,i+b_i]\) 的时候才能和后面产生联系,

所以在 \(i+a_i\) 处对单点 \(i\) 激活(\(x=-h_i\)),在 \(i+b_i+1\) 处取消(\(x=-\infty\))。

后面的节点能对 \([i-b_i,i-a_i]\) 造成贡献,故在到达 \(i\) 点后,区间 \([i-b_i,i-a_i]\)\(y\)\(h_j\)\(\max\)

然后询问挂在 \(r\),直接询问 \([l,r]\)\(x+y\) 的最值。

此时每个点是维护它为左端点的贡献,而只枚举到了 \(r\) 所以不会超界,刚好满足限制。

对于线段树为何能够轻松维护取 \(\max\) 操作的疑惑,

这是基于每个点的答案单调不减,所以直接用答案和当前取 \(\max\) 即可,当然这除了单点取消时,但这很好维护。

对应的有一个细节,就是在单点激活时可能 \(y\) 已经有值了,但是要重新赋值为 \(-\infty\),因为之前的贡献肯定不能算。

「JOISC 2019 Day2」两道料理

  • 做两道菜 \(A,B\)\(A\)\(n\) 道工序,分别需要 \(a_1,a_2,\cdots,a_n\) 的时间,对应有 \(B\)\(m\)\(b_1,b_2,\cdots,b_m\)
  • \(A\) 的每道工序还有阈值 \(s_i\) 和权值 \(p_i\),表示如果在 \(\leq s_i\) 时刻完成了工序 \(i\),就会得到 \(p_i\) 收益(可能为负)。
  • \(B\) 对应的有 \(t_i\)\(q_i\)
  • 只能将两种工序归并安排,中途不能休息,最大化最终权值和。
  • \(n,m\leq 10^6,a_i,b_i\leq 10^9,s_i,t_i\leq 2\times 10^{15}\)

神级转化,将操作放到网格图上,从 \((0,0)\) 开始,向右走一步表示做一道工序 \(a\),纵坐标对应的表示 \(b\)

\(\text{SumA},\text{SumB}\) 分别表示 \(a,b\) 的前缀和。

对于每个 \(s_i\),找到最大的 \(\text{SumB}_j\leq s_i-\text{SumA}_i\),那么对于格点 \((i,j)\),只要它在路径的左上方或者路径上就有贡献。

相似的可以对 \(t_i\) 得出一些若在路径右下或路径上就有贡献的点。

发现这一通转化只是把题面描述的可视化一些,貌似没有多好做,但实际上已经结束了。

一个左下一个右上显然不好维护,可以先把 \(p\) 全部加上,然后减去严格右下的,将 \((i-1,j+1)\) 的贡献记为 \(-p_i\) 即可。

这样就变成了最大化右下及路径上权值和,变得可做很多?

对于最后一列因为一定走到了 \((n,m)\),所以横坐标为 \(n\) 的点的贡献一定全加,那么考虑每次对前一列计算贡献。

这样就有转移式:

\[f(x,y)=\max(f(x,y-1),f(x-1,y)+s(x-1,y)) \]

\(s(i,j)\) 表示 \((i,1\sim j)\) 的贡献和(\((i,0)\) 的贡献也是必算贡献,可以初始直接计入答案)。

发现每次是对一段后缀加,然后对前缀取 \(\max\),很自然的就应当想到维护差分数组。

对于同 \(x\) 的点按照 \(y\) 从大到小加入,每次如果是正值就直接加,否则就和差分数组打架。会将一段子区间变为 \(0\)

可以理解为是操作使得 \(f(x,y-1)\geq f(x-1,y)+s(x-1,y)\)

总结一下:维护差分数组,将题意可视化的转化到坐标系上,等技巧,真的十分高效

「JOISC 2019 Day3」指定城市

  • 树上每条边是双向边,且不同方向边权不同。
  • 多次询问,每次给出 \(k\),回答指定 \(k\) 个点作为关键点后,剩余未被覆盖边权和最小值。
  • 一个点 \(x\) 若成为了关键点,那么 \(\forall (u,v,w),\text{dis}(u,x)>\text{dis}(v,x)\),它会被覆盖。(即指向这个点的边)
  • \(n\leq 2\times 10^5\)

\(k=1\) 的答案可以简单换根得到。

发现做出第一次选择之后,剩余选择点的贡献就是它到根的路径,这可以经典长剖贪心。

唯一问题是,一定有 \(\text{ans}_{i+1}=\text{ans}_i+\Delta\) 吗。事实上可以证明,这一点只对 \(i\geq 2\) 的时候成立。

对于 \(i\leq 2\) 的情况均可用换根 DP 解决。可以看做是经典模型的积累。

「JOISC 2019 Day3」开关游戏

  • 三种操作:区间异或,区间赋值 \(0\),和赋值 \(1\)。求从指定起点 01 串到指定终点 01 串的最小操作次数。
  • \(n\leq 10^6\)

观察得到:

  • 区间异或操作可以放到所有赋值操作之后。
  • 区间赋值操作互不相交。像赋值 111000111111111111 $\to $ 111000111 的操作交给区间异或!

如果得到整个串赋值后的形态,异或的次数显然是 \(s'\oplus t\) 的极长 1 连续段数。

那就随便设个状态,随便写写转移,就没了。

「JOISC 2019 Day3」穿越时空 Bitaro

  • 一排 \(n\) 个点,第 \((i,i+1),i\in[1,n)\) 称为第 \(i\) 条双向道路,它有管控时间 \([l_i,r_i]\)
  • 穿过一条道路需要 \(1\) 个单位时间,所以只能在 \([l_i,r_i-1]\) 时刻出发,从该道路一端到另一端。
  • \(q\) 次询问,每次两种操作:改变道路管控时间、询问在 \(s\) 时刻从 \(a\) 出发,在 \(t\) 时刻到达 \(b\) 的最小代价。
  • 正常走路可能不能到达,所以任意时刻可以花费 \(1\) 个代价回到上一时刻,保持位置不变。
  • \(n,q\leq 3\times 10^5\)

首先一个显然的贪心,能走就走,否则就回退到 \(r_i-1\) 然后走,于是得到了 \(4\) 分的好成绩。

然后基本的转化,将管控时间变为 \([l_i-i,r_i-i-1]\),就去除了时间自然流逝的干扰。

然后需要有一定积累,可以识别出每条路就是个分段函数,然后结合单点修改操作,精准识别这是线段树题。

关键就是设计出具有结合律的分段函数合并方式,可以用三元组 \((a,b,c)\) 记录。

表示走这个区间里的路需要在 \(\leq a\) 时刻到达,中间消耗 \(c\) 的代价,在 \(b\) 时刻到达终点。

初始给定的实际上仅是二元组,两个二元组如果有交就直接取交,否则就会产生三元组。

分别讨论二元组和三元组的合并即可,都是依据贪心策略合并,仔细想想不会有大问题,talk is cheap

struct node {
	int o, a, b; LL c;
	node (int o_ = 0, int a_ = 0, int b_ = 0, LL c_ = 0) {
		o = o_, a = a_, b = b_, c = c_;
	}
	node operator + (const node &p) const {
		if(! o && ! p.o) {
			if(b < p.a) return node(1, b, p.a, 0);
			if(a > p.b) return node(1, a, p.b, a - p.b);
			return node(0, max(a, p.a), min(b, p.b), 0);
		}
		else if(! o && p.o) return node(1, min(b, max(a, p.a)), p.b, p.c + max(0, a - p.a));
		else if(o && ! p.o) return node(1, a, max(p.a, min(b, p.b)),   c + max(0, b - p.b));
		else return node(1, a, p.b, c + p.c + max(0, b - p.a));
	}
};

细节方面,可能有 \(t<s\) 的情况,所以可以整体 reverse 然后做两遍。还要特判 \(s=t\) 的情况。

「JOISC 2019 Day4」蛋糕拼接 3

  • \(n\) 个蛋糕中选出恰好 \(m\) 个,再任意重排,每个蛋糕有两个权值 \(v_i,c_i\),最大化:

    \[\sum_{i=1}^m v_{k_i}-\sum_{i=1}^m |c_{k_i}-c_{k_{i+1}}| \]

  • 这里令 \(k_{m+1}=k_1\),即蛋糕成环。

  • \(m\leq n\leq 2\times 10^5,1\leq v_i,c_i\leq 10^9\)

显然前一个和式与顺序无关,后面一个和式最优情况下就是 \(2(c_{\max}-c_{\min})\),因为是任意选择所以不妨先将点按照 \(c_i\) 排序。

然后并没有什么好方法能维护这个求和,包括但不限于枚举左端点、cdq 分治等常见的优化方法。

于是大胆猜决策单调性,然后就可以直接分治,结合主席树求区间前 \(m\) 大和,就能做到 \(O(n\log ^2n)\)

注意决策单调性不等价于函数是凸的,所以双指针的是不行的,这个结论大概只能打表求出?

实现细节,记得主席树的空间是 \(4n+n\log n\) 的,所以这里不能开 \(20n\) 而是至少 \(22n\)

「JOISC 2019 Day4」合并

  • 树上每个节点属于某个州,若能够将树断开一条边,使得两个连通块之间不存在同州的节点,那么称这个树不稳定。
  • 每次可以合并两个州,求使得树变得稳定的最小合并次数。

简单但需要一定思维的。

首先将所有断开后满足条件的边处理出来,把它们都断开后,所有连通块可以合并成一个节点。

再把它们连回来,构成新树,相当于每个节点颜色均不同,而每次可以合并树上一条路径,需要把树缩成一个点。

等价于把树用最少链覆盖,经典结论,答案是 \(\left\lceil \cfrac{\text{leaf}}{2}\right\rceil\)

「JOISC 2019 Day4」矿物

  • 交互题,在长度为 \(2n\) 的序列中,每种数恰好出现两次,需要确定相同的数对。
  • 每次可以把一个数扔进集合,或把一个集合中的数扔出来,会回答操作后集合中数的种类数。
  • \(n\leq 4.3\times 10^4\),只能使用 \(\leq 10^6\) 次操作。

首先问遍集合就能得到每个位置在配对的左边还是右边,然后用右边找左边。

然后类似整体二分,每次将一些左边的数放入集合,然后问遍右边的数,看它的左边是否在里面。

还需要一些合理的卡常技巧。

posted @ 2022-11-19 21:26  LPF'sBlog  阅读(397)  评论(0编辑  收藏  举报