AGC 做题合集 #5

书接上回,代码可以看 这里

  1. AGC018D Tree and Hamilton Path[1]
  2. AGC014D Black and White Tree[2]
  3. AGC013C Ants on a Circle[3]
  4. (VP)AGC028C Min Cost Cycle[4]
  5. (VP)AGC028B Removing Blocks[5]
  6. (VP 补题)AGC028D Chords[6]
  7. AGC016D XOR Replace[7]
  8. AGC016E Poor Turkeys[8]
  9. AGC016F Games on DAG[9]
  10. (VP 补题)AGC032D Rotation Sort[10]

  1. AGC018D Tree and Hamilton Path

    有一颗 \(N\) 个顶点的树,顶点依次标号 \(1\sim N\)

    \(i\) 条边连接着顶点\(A_i\)\(B_i\),且第 \(i\) 条边的长度为 \(C_i\)

    有一张 \(N\) 个点的完全图,图上两点之间的边的边权为它们在树上的距离。

    求最长哈密顿路径(即不重不漏恰好经过每个点一次)。

    \(2 \le n \le 10^5\)


    WA 了 \(\infty\) 发后终于猜对了结论!

    首先,我们令第 \(i\) 条边 \((x_i, y_i, w_i)\) 中的 \(y_i\) 为深度更大的点,可以猜测上界为 \(L = \sum_{i} 2 \min\{n - siz_y, siz_y\} w_i\),然后手玩样例可以发现,这个上界在哈密顿回路下面是成立的,于是我们只要确定起点终点 \((a, b)\),然后答案就是 \(L - dis(a,b)\)

    一个朴素的想法是,我们让 \((a, b)\) 是相邻的,这样我们只要减去一条边的贡献即可,于是选择最小的边。

    接着我们会意识到,有的点对是不可能在一起的,比如如果一条边将树分成了两个大小相同的块,那么一定只能选这条边(样例 2)。

    接着我就一直以为这是一个特殊情况,于是没有推广,然后一直因为这个 WAWA……

    考虑推广上面的结论,一个点对 \((a, b)\) 是不能选择的,当且仅当存在一条边,将树分成了大小为 \(u, v\) 的两个块并且有 \(u \ge v\)\((a, b)\)\(v\) 这个块里面。具体地说,我们每次在两个点中间跳的时候,如果两次都在同一个块内,那么一定是那个大一点的块,不然不能达到上界,而一旦起点终点占了两个点,就会导致中途出现空缺,于是达不到上界。

    显然这样的边要么和 \(a\) 相邻,要么和 \(b\) 相邻,扫一扫就可以判断 \((a, b)\) 的合法性了。 ↩︎

  2. AGC014D Black and White Tree

    • 给出一颗 \(N\) 个节点组成的树,每个节点都可以被染成白色或者黑色;

    • 有高桥(先手)和青木(后手)两个人————高桥可以把任意一个点染成白色,青木则可以把任意一个点染成黑色,每个点只可染色一次。

    • 重复上述操作直到所有点都被染色后,只执行一次执行以下操作:

      1. 把所有青木染成黑色的节点的相邻的白点感染成“次黑色”。
      2. 次黑色不能继续感染白点。
    • 若操作完毕后仍还有白点存在,即高桥(先手)胜,反之则青木(后手)胜。

    • 现在给出这棵树,问当前此树是先手必胜还是后手必胜。

    \(2 \le N \le 10^5\)


    首先,要求就是一个白点旁边一定要有一个黑点。

    因此考虑递归判断,我们考虑最特殊的情况,对于一个叶子 \(x\),如果其父亲 \(y\) 下面有两个以上的儿子,那么可以直接让 \(y\) 变白,之后无论如果都会至少一个叶子是白色,先手必胜。如果 \(y\) 下面只有 \(x\),那么我们直接让 \(y\) 变白,接着 \(x\) 会变黑,那么对于 \(y\) 的父亲 \(z\)\(y\) 是不会有任何影响了,可以视作删除了 \(x,y\) 两个点了。

    于是只要一个非叶子为根,每次考虑最深的叶子然后删除它和父亲即可判断了。


    写完了,我们就会发现,这个实际上是要求这个树存在一个完美匹配!于是策略也比较明白了,每选一个点,下一个人直接选这个点的匹配即可。 ↩︎

  3. AGC013C Ants on a Circle

    有一个长度为 \(L\) 的圆环,上面有 \(N\) 个蚂蚁,位置分别为 \(x_i\),运动方向为 \(d_i\)\(1\) 表示顺时针,\(2\) 表示逆时针。

    每只蚂蚁将会同时开始以单位速度运动,如果两只蚂蚁相遇, 那么它们会改变自己的方向继续运动。

    \(T\) 秒之后每只蚂蚁的位置。

    \(1 \le N \le 10^5, 1 \le L \le 10^9\)


    这个题比较妙妙妙啊。

    首先,如果我们不管改变方向,一只蚂蚁一直爬爬爬,\(T\) 秒后到的位置集合一定是最后所有蚂蚁到的位置的集合。

    如果考虑改变方向,那么每只蚂蚁一定是来回转转转,最后所有蚂蚁的相对位置不变。

    考虑从 \(0\) 开始,将环切为一条链,于是我们只要确定了 \(1\) 号蚂蚁最后在第几个(记为 \(t\)),我们就可以确定所有蚂蚁的位置了。

    对于所有蚂蚁,如果它顺时针穿过 \(0\),那么所有蚂蚁前面都会少一只蚂蚁(除了它),如果逆时针穿过 \(0\),那么所有蚂蚁前面都会多一只蚂蚁。即第一种情况 \(t \gets t - 1\),第二种情况 \(t \gets t + 1\),于是第一只蚂蚁的位置可以确定了。 ↩︎

  4. AGC028C Min Cost Cycle

    • 给定一个 \(n\) 边的有向完全图,每个点有两个点权 \(a\)\(b\),一条边 \((u,v)\) 的边权值的计算方法为 \(\min(a_u,b_v)\)
    • 求边权和最小的哈密顿回路的边权和。
    • 对于 \(100\%\) 的数据,\(2 \le n \le 10^5\)\(1 \le a,b \le 10^9\)

    随机数开题 yyds!VP 的时候不信随机数的开题顺序,看了一眼 C 就想 B 去了,结果 B 自闭了,然后再看一眼 C 秒了,接着看 B 也会了。

    首先考虑下界应该是什么,我们把 \(\{a_i\}, \{b_i\}\)\(2n\) 个数中的前 \(n\) 小拿出来,这样下界就是这些数之和。

    观察样例,我们把前 \(n\) 小的数在原来的序列上面标记一下,如果满足以下几个条件,就是合法的:

    • 全部是 A。
    • 全部是 B。
    • 存在一个 \(i\) 满足,\(a_i, b_i\) 都没有标记。

    然后发现这个结论非常正确,于是只要按照这个结论调整一下选择即可。不想证明了。 ↩︎

  5. AGC028B Removing Blocks

    \(N\) 块砖块排列成一行,从左到右编号为 \(1\)\(N\) 。每一个砖块都有一个重量,砖块 \(i\) 的重量为 \(A_i\)。 Snuke 会对这些 \(N\) 个砖块执行如下操作:

    • 选择一个还没有被移除的砖块,然后移除它。这个操作的代价是与被移除的砖块相邻的砖块(包括它自己)的重量之和。我们定义两块砖 \(x\)\(y ~(x \leq y)\) 是相邻的,当且仅当对于所有 \(z (x \leq z \leq y)\) ,砖块 \(z\) 仍然没有被移除。

    \(N!\) 种移除砖块的可能顺序。你需要对于所有可能的顺序计算出移除完所有 \(N\) 块砖块的代价,并计算这些代价的和。由于答案可能非常大,答案需要对 \(10^9+7\) 取模。

    \(1 \le N \le 10^5\)

    想了半天的 DP 自闭了,结果突然想到计算贡献后这题就没了。

    首先,我们如果根据点的选择先后顺序构建一棵笛卡尔树,即按顺序选择一个点,然后将整个区间劈成两半,接着递归构造。

    于是一个点的贡献就是其在所有笛卡尔树上的深度之和 \(\times a\)

    然后一直想着 DP

    既然已经开始考虑贡献了,我们不妨继续考虑贡献,我们注意到,我们可以枚举 \(x,y\)(这里先假设 \(x<y\)),然后计算 \(y\)\(x\) 父亲的方案数,这些方案中就会使得 \(x\) 深度 \(+1\)

    显然,设 \(d = y - x+1\),那么方案数就是 \(\binom{n}{d} (n - d)! (d - 1)!\),注意到这个式子只和 \(d\) 有关,于是枚举 \(d\) 即可计算。 ↩︎

  6. AGC028D Chords

    给定一个圆, 圆上均等地放着 \(2n\) 个点, 已有 \(k\) 对点之间连好了线段, 从中选择剩下 \(n−k\) 对点随意连线段(每个点只连一条线段)。

    两点联通当且仅当两点在同一条线段上或两点所属于的线段相交, 求所有连边方案中, 联通块的个数和。

    \(1 \le n \le 300\)


    想了半天终于会了没有限制点对的情况,然后怎么都不会了/kk。

    怎么这场一堆考虑贡献的题目啊?!

    首先这个题目的圆是无意义的,和直线差不多。

    我们考虑取出一个连通块的最左边的点和最右边的点 \((l, r)\),首先这两个点一定属于同一个联通块,其次,这两个点中间的所有点的连边都没有越过 \([l, r]\)

    于是可以考虑枚举 \((l, r)\) 计算一个连通块是 \([l,r]\) 的方案数,所有方案数相加就是连通块的个数之和。

    我们设 \(f(l, r)\) 表示答案,记 \(cnt(l, r)\) 表示 \([l,r]\) 中没有限制连边的点数,记 \(g(k)\) 为如果有 \(k\) 个点没有限制,这 \(k\) 个点两两连边的方案数是多少,显然 \(g(k) = [k \bmod 2 = 0] \frac{k!}{2^{\frac{k}{2}} (\frac{k}{2})!} = [k \bmod 2 = 0] 1 \times 3 \times \dots \times (k - 1)\),就是先随意排列,然后消除重复的排列方案。

    如果不考虑 \(l,r\) 在同一个连通块,那么方案就是 \(g(cnt(l, r))\),接着考虑容斥,枚举 \(l\) 所在连通块,减去不合法的即可。

    于是 \(f(l, r) = g(cnt(l, r)) - \sum_{i = l}^{r - 1} f(l, i) g(cnt(i + 1, r))\),直接区间 DP 即可,复杂度 \(\mathcal O(n^3)\)↩︎

  7. AGC016D XOR Replace

    一个长度为 \(n\) 序列 \(\{a_i\}\),一次操作可以将某个位置变成整个序列的异或和。问最少几步到达目标序列 \(\{b_i\}\),不行则输出 \(-1\)

    \(1 \le n \le 10^5\)


    对于操作类型问题,如果你觉得它难,就是没有发现操作的不变量 / 更简单的操作表示形式。

    这个题就是后者。每次变成异或和是比较玄乎的,但是我们观察整个序列的异或和的变化,比如我们操作的是 \(x\),之前的异或是 \(y\),那么我们操作后这个数字变成了 \(y\),但是异或和就是 \(x\) 了。这个启发可以令 \(a_{n + 1}\) 为序列的异或和,然后每次操作就是交换 \(n+1\) 和任意一个位置上的数字。

    令异或和为 \(val\),那么可以达到目标的充要条件就是 \((val \cup \{a_i\}) \subseteq \{b_i\}\)

    接着我们考虑最小步数,对于 \(a_i \neq b_i\),我们就连一条 \(a_i \to b_i\) 的边,如果所有的值构成了一个环,并且 \(val\) 是一个孤立点,那么步数就是环长,如果 \(val\) 和所有值一样构成了一个环,那么步数就是环长 \(- 1\),因为我们不管将所有点校正后 \(val\) 可以不用回来,其他的要回来。

    于是答案就是边数 + 连通块数目 - [\(val\) 不是孤立点](最后一步让 \(val\) 不回来) ↩︎

  8. AGC016E Poor Turkeys

    \(N(2\le N\le 400)\) 只火鸡,编号为 \(1\)\(N\),有 \(M(1\le M \le 10^5)\) 个人,每人指定了两只火鸡 \(x\)\(y\)

    1. \(x\)\(y\) 都活着, 那么这个人将会等概率地随机吃掉一只。
    2. \(x\)\(y\) 恰好活着一只, 那么这个人将会吃掉活着的这只。
    3. \(x\)\(y\) 都已经死亡, 那么只好什么都不做。

    注意,第 \(1\) 个人到第 \(M\) 个人每个人依次行动。求有多少个 \((i,j)(1\le i<j \le N)\) 满足在最终时刻第 \(i\) 只火鸡和第 \(j\) 只火鸡可能都还活着。


    很久以前写的,补一发题解。

    考虑如果最后要让 \(i\) 活下来,我们应该干什么,肯定要拉一堆火鸡垫背,于是我们可以设 \(f(i, j)\) 表示如果 \(i\) 最后存活,那么是否一定要拉 \(j\) 垫背。

    我们发现,如果正着考虑,每只火鸡生死未卜,无从下手,于是可以发动时间倒流技能!接下来的每次考虑,如果 \(f(i, x)\)\(1\),那么表示 \(x\) 在后面会被杀,为了保证后面有的杀,于是 \(x\) 在当前时刻一定不能杀,于是可以视为 \(x\) 有一个免死金牌,特殊的 \(f(i, i) = 1\)(我们假设最后杀 \(i\))。

    倒着考虑每个 \(x\), \(y\),如果 \(x, y\) 全被拉去垫背了,因为这次一定会拉一个毙了,于是后面存在某一次没有垫背的了,于是 \(i\) 一定活不到最后;如果 \(x, y\) 有一个被拉去垫背了,为了让那个时候还能垫背,于是我们可以把另一个也给毙了;如果两个都没有确定是否垫背,那么我们也什么都不能确定。

    最后考虑每个最后有希望活下来的 \(i, j\),如果存在一个 \(x\) 满足 \(f(i, x) = f(j, x) = 1\),那么意味着,我们要在某一回合一定因为保留 \(i / j\) 要杀了 \(x\),但是这个 \(x\) 又有免死金牌,必须得活下去,后面 \(j / i\) 需要他垫背,产生矛盾,\(i,j\) 一定活不到最后。于是只要 \(f(i), f(j)\) 没有公共元素即可活下去。 ↩︎

  9. AGC016F Games on DAG

    给定一个\(n\)个点\(m\)条边的DAG,对于每条边\((u,v)\)都满足\(u<v\)\(1,2\)号点各一个石头,每次可以沿DAG上的边移动一颗石头,不能移动则输,求所有\(2^{m}\)个边的子集中,只保留这个子集先手必胜的方案个数。

    \(n \le 15, m \le n ^ 2 / 2\)


    首先,如果给定一张图,我们应该如何判断胜负呢?显然,一个点的 \(\rm SG\) 函数就是其所有后继点的 \(\rm SG\)\(\rm mex\),最后只要 \(1, 2\) 点的 \(\rm SG\) 不同就是先手必胜了。

    我们考虑最后的 SG 函数长什么样:

    • 对于 \(\rm SG\)\(x\) 的点的集合,我们记为 \(S_x\)
    • \(S_x\) 内部不能有边。
    • \(\forall y < x\)\(S_x\) 中的每个点必须要向 \(S_y\) 中的至少一个点连边。
    • 对于 \(y > x\)\(S_x\) 中的每个点向 \(S_y\) 中点连边的情况是任意的。

    于是可以考虑 DP 了,我们记 \(f(s)\) 表示只考虑 \(s\) 集合中的点,并且满足 \(1, 2\)\(\rm SG\) 函数一样的方案数(\(1, 2 \in s\), 否则不合法),最后答案就是 \(2^m - f(U)\)了。

    考虑转移,我们只要确定当前最小 \(\rm SG\) 集合就是了,于是可以枚举 \(t \subsetneq s\)(必须同时包含 / 不包含 1, 2,至于为什么是真子集,是因为如果和 \(s\) 相同,就是全部不能连边,方案为 \(1\),可以直接累加到 \(s\)),表示这一个部分的点的 \(\rm SG\) 函数是更大的,而 \(s / t\) 部分的 \(\rm SG\) 函数是更小的,如果 \(t\) 包含了 \(1,2\),那么就可以算出系数递归问题到 \(f(t)\),如果没有包含,那么 \(t\)\(\rm SG\) 的相同情况也是不重要的,可以任意连边,这些都是比较好计算的。 ↩︎

  10. AGC032D Rotation Sort

    给定一个排列,你可以花费 \(A\) 使一个区间最左边的数跑到最右边,或者花费 \(B\) 的代价使最右边到最左边,求把整个序列变成升序的最少花费。


    首先一个点只会被操作一次(我们定义被操作就是指 ShiftLeft 中的最左边元素被操作,ShiftRight 同理),如果操作多次完全可以一次进行。

    接着,我们考虑最后不会被操作任何一次的数,显然这些数会形成一个上升的序列,至于其他的数,如果它要比后面的一个在该序列中的数字大,那么就要 ShiftLeft 一次到右边,否则我们视为要 ShiftLeft 一次。

    于是可以直接记 \(f(i)\) 表示只考虑前 \(i\) 个元素,其中第 \(i\) 个元素是在这个序列中且所有元素排好序的最小代价,直接根据上面的规律转移即可,复杂度 \(\mathcal O(n^2)\)↩︎

posted @ 2022-07-04 14:34  Werner_Yin  阅读(100)  评论(2编辑  收藏  举报