XXI Open Cup Grand Prix of Korea 题解

只做完了 场切的 几题

A - Advertisement Matching

\(N\) 个广告,\(M\) 个人,第 \(i\) 个广告需要分给 \(a_i\) 个人观看,第 \(i\) 个人只能收到不超过 \(b_i\) 个不同的广告。\(Q\) 次操作,每次选择一个 \(a\)\(b\) 增加或减少 \(1\),每次操作之后求问能否把所有的广告都分配完。\(N,M,Q,a_i,b_i\le 2.5\times 10^5\)

首先不难看出一个二分图模型:第 \(i\) 个左部点需要匹配 \(a_i\) 个右部点,第 \(i\) 个右部点最大匹配 \(b_i\) 个左部点。然后判断是否存在方案使所有左部点都匹配完。

接下来引入一个 Gale–Ryser 定理,在本题中可以写成:先将 \(a\) 降序排序,那么若存在方案,当且仅当 \(\forall k\in[1, N]\) 都有 \(\sum_{i=1}^k a_i\le \sum_{i=1}^M \min(b_i,k)\) 成立。下面是证明:

先建立网络流模型:源点向左边连边,容量 \(a\);右边向汇点连 \(b\) 容量边;左右部点之间都连一条 \(1\) 容量边。现在需要证明最大流 \(\ge \sum_{i=1}^N a\),等价于最小割 \(\ge \sum_{i=1}^N a\)

考虑一个割,源点这边左部点记作 \(S\),右部点记作 \(T\)。那么最小割可以表示为:

\[\sum_{i\notin S} a_i+\sum_{i\in T} b_i + |S|\times(M-|T|) \]

\(|S|=k\),那么将 \(a\) 降序排序后(记作 \(a'\))有:\(\min_{S}\{\sum_{i\notin S} a_i\} = \sum_{i=1}^k a'_i\)。而后两个和式又可以写成 \(\sum_{i\in T}b_i+\sum_{i\notin T}k\)。贪心地考虑,要使其最小化,那么一定将大于 \(k\) 的那些 \(b_i\) 换为 \(k\)。那么最终最小割为:

\[\sum_{i=1}^k a'_i+\sum_{i=1}^M\min(b_i,k) \]

然后就对于每个 \(k\),维护出 \(\sum_{i=1}^M \min(b_i,k)-\sum_{i=1}^k a_i\) 即可。这个 \(\min\) 非常恶心,考虑一个巧妙的转化:设 \(c_k = \sum_{i=1}^M [b_i\ge k]\),即不小于 \(k\)\(b\) 的个数。我们发现原式 \(=\sum_{i=1}^k (c_i-a_i)\),简洁了许多,可以线段树维护。那么怎么修改呢?

  • 对于修改 \(b\),由于只有 \(1\) 的变化量,不难发现只需要修改 \(c\) 的一个位置就行;
  • 对于 \(a\),我们可以在排好序的 \(a'\) 上找到第一个或最后一个对应值的位置(二分),然后直接在 \(a'\) 上改掉。由于变化量为 \(1\),不会改动原来 \(a'\) 的降序。

最后复杂度为 \(O(N\log N)\)

C - Economic One-way Roads

给定一个 \(N\) 个点的无向图,每条边需要被定向,\(a_{i,j}\) 表示将 \(i,j\) 之间的边定向为 \(i\to j\) 的费用。如果 \(a_{i,j}=-1\) 说明原图中不存在连接 \(i,j\) 的边。你需要用最少的总费用给原图中的边定向,使得整张有向图强连通。\(N\le 18,a_{i,j}\in[-1, 10^6]\)

首先需要知道,一张图强连通,当且仅当可以通过以下方式构造:

维护一个点集 \(V\),首先任意选择一个点 \(v\),加入 \(V\) 中。然后重复执行以下操作:

  • \(V\) 选出任意两个点 \(x,y\)\(x\) 可以等于 \(y\));
  • 找出若干个 \(\notin V\) 的点 \(\{u_1, u_2, \cdots, u_k\}\)(可以不选任何的点),然后连接 \(x\to u_1 \to u_2 \to\cdots \to u_k \to y\),并将 \(\{u_1, u_2, \cdots, u_k\}\) 加入点集 \(V\)

这种方法被成为“耳分解”,上面每次选出的那个路径就是“耳”。

根据这个我们有一个朴素的状压 dp:\(f(S)\) 表示选出点集 \(S\) 构成强连通图的最小选择的总边花费和。那么对于每个状态 \(f(S)\),都可以枚举一遍 \(S\) 补集的子集作为“耳”,然后还有 \(O(|S|^2)\) 种方法选择“耳”的两端。总复杂度为 \(O(3^N N^2)\)

这样的方法不仅需要优化,而且存在正确性的问题:可能存在一条边正反都没有记入答案,从而结果偏小。有一种巧妙的解决方法是:对于一条未定向的边,两个方向的花费分别为 \(a,b\)。这总得选一条吧?那么不妨先将 \(\min(a,b)\) 加入答案,然后把两个方向分别用 \(a-\min(a,b)\)\(b-\min(a,b)\) 计算。这样就能直接拆开了。

考虑优化:引入 \(g(S,u,v)\) 为当前构造的“耳”还需要一条连接 \(u,v\) 的路径,强连通部分以及 \(u,v\) 的非完整“耳”构成的点集为 \(S\)。容易发现,记录“耳”的端点的好处在于,可以直接从 \(u,v\) 开始拓展而不是盲目地枚举集合。

复杂度可以做到不超过 \(O(2^N N^3)\),当然实现转移还是有及其多的细节的。

D - Just Meeting

求构造一个 \(N\times N\) 的矩阵 \(C\),满足 \(\forall i\in [1, n]\),都满足 \(\forall\) 不同于 \(i\)\(j,k(j\ne k)\),有 \(C_{i,j}\ge \min(C_{i,k},C_{k,j})\)。并且 \(C_{i,j}=C_{j,i}\)。现有 \(M\) 个位置已经有固定值,除这些位置外都可以任意选择数字。求所有可行构造方案中 \(\sum_{i=1}^n\sum_{j=i+1}^nC_{i,j}\) 的最小值。\(N,M\le 3\times 10^5\),方案中的 \(C_{i,j}\in [1, 10^7]\)

如果将 \(C\) 矩阵看做图的邻接矩阵的话,那么相当于要构造一个 \(N\) 个点的完全图,满足 \(\forall i\ne j\),不存在一个 \(k\) 使 \(C_{i,j}\le \min(C_{i,k}, C_{k,j})\)。也就是说 \(i,j\) 间不存在一条长为 \(2\) 的路径其上最小比边权小于 \(i,j\) 之间的边。

考虑一个三元组 \((i,j,k)\),要使之满足条件,不得存在一条边严格小于其他两条边。那么小小讨论一下:

  • 三点间不存在边:要求最小化 \(C\) 的总和必然是三个 \(1\) 啦;
  • 只存在一条边:另外两条也是 \(1\)
  • 存在两条:由于新加入的边不能作为最小的,原来两条中最小的也不能让它一个最小,于是新边权必然为原来两条中的较小者;
  • 存在三条:现在就由不得选了,反而应该检查是否合法。

那么拓展到多个点的情况,可以重复以上加边操作,直到补成完全图。可以证明不会因为补上的边突然违反约束。

不难发现,倘若我们先求出一个原图的最大生成森林,对于一条未补上的边 \((i,j)\),树上路径的最小值(原图的瓶颈路)就可以作为这条新边的权值。对于原来存在但不属于最大生成森林的边,其边权应该与树上路径的最小值相等:如果小了那么它会成为某个三元环的唯一最小值,大了又会导致路径上那条最小边成为唯一最小值。

最后实现的话,掏出一个 Kruskal 重构树就没了。复杂度 \(O(N\log N)\)

E - Chemistry

给定一个 \(N\) 个点 \(M\) 条边的无向图,求有几个区间 \([l,r](1\le l\le r\le n)\),满足仅保留编号 \(\in[l,r]\) 中的点可以恰好构成一条链。\(N,M\le 2.5\times 10^5\)

“一条链”的条件是很复杂的,考虑进行拆解:

  • 没有环;
  • 每个点度数不超过 \(2\)
  • 连通块个数为 \(1\)

很显然这三个限制叠加就和链的限制等价,那么考虑对于每个右端点 \(i\),左端点最前面可以达到什么位置,使得这个区间不存在环,定义为 \(f_i\)。同理对第二个限制定义 \(g_i\)

假设通过某种手段求出了 \(f,g\),那么只要统计有几个 \(j\in [\min(f_i,g_i),i]\) 满足区间中的点只有一个连通块即可。根据“点减边”的套路,我们可以维护每个左端点与当前右端点的点减边结果,计算有几个是 \(1\) 就行了。考虑线段树维护这个东西,每次右端点右移,左侧的所有值 \(+1\),然后遍历当前右端点的边将边的影响加上即可。怎么维护出 \(1\) 的个数呢?注意到一张不空的图的连通块不可能有 \(0\) 个或者更少,也就是说 \(1\) 是可能的最小值,而最小值的个数维护有手就行。这部分复杂度 \(O(N\log N)\)

考虑求 \(f,g\) 怎么搞。首先一个重要的性质:如果 \([j,i]\) 不合法,那么 \(\forall k<j, [k,i]\) 都不合法。掏出一个双指针,用一个 LCT 整出 \(f\),开个桶整出 \(g\) 就行了。这里复杂度 \(O(N\log N)\)

最后思考一个问题:为什么预处理的 \(f,g\) 不能适用第三个限制?因为连通块个数并不随着左端点的左移而单调不增或不减。

F - Interval Graph

给定 \(N\) 个闭区间,第 \(i\) 个为 \([s_i, e_i]\),权值为 \(w_i\)。定义这 \(n\) 个区间组成的“区间图”为,\(i, j\) 之间存在一条无向边当且仅当 \([s_i, e_i]\cap[s_j,e_j]\ne \varnothing\)。现在要求移除其中若干个区间,使剩下区间构成的区间图为森林。求保留区间权值和的最大值。\(N\le 2.5\times 10^5, 1\le s_i\le e_i\le 5\times 10^5,w_i\in [1, 10^{12}]\)

首先考虑一些区间的区间图是森林意味着区间之间有什么特征:森林说明没有环,而一个区间图不存在环的充要条件是:不存在一个位置 \(p\),使得存在三个互不相同的 \(i, j, k\) 满足:\(p\in [s_i, e_i]\cap [s_j, e_j]\cap [s_k, e_k]\)。也就是说不能有一个位置上面覆盖三个及以上个区间。

那么我们考虑一个网络流模型:

  • 一开始我们有 \(2\) 的流量:一个位置最多可以同时存在两个区间。
  • 对于每个区间 \([s_i, e_i]\),我们要走就会把他走完,那么连边 \(s_i \to (e_i + 1)\),容量为 \(1\),表示在 \([s_i, e_i]\) 的位置这个区间我们可能会消耗一个流量。费用显然为 \(w_i\)
  • 对于每个位置 \(p\),连边 \(p\to (p+1)\),容量为 \(2\),表示兼容该位置选零到二个区间三种情况。

然后发现要保留尽量大的,于是将费用取相反数,就可以跑费用流了。

然后 SPFA 貌似死了,考虑使用 Dijkstra,但很显然有负权,而传统解决方案中的势能需要 SPFA。

但是我们发现这个图是个 DAG!所以 dp 一下就可以求出势能了。

还有更简单的方法:设第 \(i\) 个位置的势能为 \(-10^{12}\times i\) 即可。但是这个我写炸了

最后时间复杂度 \(O(N\log N)\)

H - Alchemy

有一个可重集合,元素 \(i(\in[0, N ))\)\(c_i\) 个。每次可以选择一个子集 \(S\),在原集合中删去这些元素,重新插入一个 \(\text{mex}(S)\)。求最终可以得到的最大的权值的元素。\(N\le 10^5\)

考虑将操作倒过来:每次选定一个元素 \(k\),然后:

  • \(k=0\):插入任何数量的任意 \(>0\) 的元素;
  • \(k\ne 0\):插入任意数量(\(>0\))的 \(<k\) 的元素,\(>k\) 的随意。

如果以上操作若干次之后得到了原集合的子集那么 \(k\) 是可行的。

实际上可以将上面操作简化:

  • \(\{k\}\to \{t| 0\le t< k\}(k>0)\)
  • \(\{0\}\to \{k\}(k>0)\)

很显然新加入的多了不会比少了更容易成为原集的子集,于是这样简化是正确的。

那么对于一个 \(k\) 从右往左扫一遍就能 \(O(N)\) 判断是否可行。

然后发现这个东西单调,可以二分答案,复杂度 \(O(N\log N)\)

J - Remote Control

在一个二维平面上,有一个在 \((0,0)\) 处的障碍。一开始给定一个操作序列,长度为 \(N\),序列中的每个操作为上下左右只一。现有 \(Q\) 次询问,每次在 \((x,y)\) 放一个遥控车,并执行一次操作序列,遇到前面有障碍则忽略这一次操作。求最终位置。\(N,Q,|x|,|y|\le 3\times 10^5\)

考虑每次移动车的复杂度是 \(O(NQ)\) 的,无法承受。那么不妨换个角度:车有很多个,但障碍只有一个对吧。那倒不如,直接一次性放完所有的车,然后用障碍去推,而不是用车去模拟。

具体的,先保存所有车的信息,然后对障碍执行操作序列,只不过都是反操作(左对右,上对下)。如果碰到了有车的位置,那么把这些车往对应方向再挤一个单位。

实现时可以用一个 std::map<std::pair<int, int>, std::set<int> > 保存每个位置对应的车的集合,推车时做一遍 std::set 的启发式合并就能保证复杂度。

最后算答案时,将期望移动到的位置算上推车的影响即可。复杂度 \(O(N\log^2 N)\),当然也有 \(O(N\log N)\) 的方法。

K - Sewing Graph

有一块布,上面有 \(N\) 个点 \(\{(x_i,y_i)\}\),你需要求一个序列 \(\{s_i\}\),设长度为 \(K\),对于 \(1\le i< K\),若 \(i\) 为奇数,在布的正面连接 \(s_i,s_{i+1}\),反之在反面连。若最终正反面的图都联通,则 \(\{s_i\}\) 合法。求构造一个最短的合法的 \(\{s_i\}\)\(N\le 1000, 1\le x_i,y_i\le 10^9\)

Solution 1

考虑 \(N\) 个点排成一条直线的情况:显然依次连过去就是答案。

那么怎么对任意的点集可以“依次连过去”呢?

将所有点以 \(x\) 为第一关键字,按 \(y\) 为第二关键字排序,最后直接连肯定不相交。复杂度 \(O(N\log N)\)

Solution 2

假如说两对点 \((a,b)\)\((c,d)\) 之间的线段有交怎么办?换成 \((a,c)\)\((b,d)\) 之后发现欧几里得距离和一定更小。

于是暴力 Kruskal 求出欧几里得最小生成树,然后正反两面都可以用这棵树。最后对这个树求个欧拉序就行了。复杂度 \(O(N^2\log N)\)

posted @ 2021-03-05 15:40  -Wallace-  阅读(835)  评论(1编辑  收藏  举报