AGC 做题合集 #3

  书接上回,代码去这里看。

  1. "AGC029D Grid game"[1]
  2. "AGC021D Reversed LCS"[2]
  3. "AGC035E Develop"[3]
  4. "AGC017F Zigzag"[4]
  5. "AGC025E Walking on a Tree"[5]
  6. "AGC052D Equal LIS"[6]
  7. "AGC003E Sequential operations on Sequence"[7]
  8. "AGC006C Rabbit Exercise"[8]
  9. "AGC007D Shik and Game"[9]
  10. "AGC007E Shik and Travel"[10]

  


  1. AGC029D Grid game

    高木和青木正在玩一个游戏。

    具体地说,他们有一个 \(H\times W\) 的矩阵,上面有 \(N\) 个障碍物。

    在起点 \((1,1)\) 处有一颗小石子,高木先手,和青木将轮流进行以下操作:

    • 假设当前石子所在的位置为 \((x,y)\) ,那么如果是轮到高木,他可以选择将石子移动到 \((x+1,y)\) 或者不移动。青木可以将石子移动到 \((x,y+1)\) 或者不移动。
    • 石子移动到的地方不能是障碍物或者矩阵外面。

    当一轮操作中高木和青木都没有移动石子时,游戏结束。

    现在,高木想尽可能地让游戏轮数变多,而青木则会尽可能地让游戏轮数变少。

    请问在双方都采取最优策略地情况下,会进行几轮游戏(最后一轮无法操作也算做一次)。

    \(H, W \le 2\times 10^5, 0 \le N \le 2\times 10^5\)


    可以直接秒的大水题。

    显然只要看出高木必须移动之后就没有任何难点了。

    考虑到了以 \(i\) 轮,同时处理出最远可以到的列,那么如果有一个障碍是可以碰到的,那么青木一定会让高木撞上然后结束游戏。 ↩︎

  2. AGC021D Reversed LCS

    定义一个字符串 \(T\) 权值为 \(T\)\(T'\)(翻转) 的最长公共子序列长度。

    你现在有一个 \(S\),你可以修改任意 \(k\) 个字符,求最大权值。

    \(k \le |S| \le 300\)


    结论:这个求的是最长回文子序列长度。证明不会。

    直接区间 DP 即可。 ↩︎

  3. AGC035E Develop

    在黑板上写有 \(-10^{18}\)\(10^{18}\) 中的所有整数,每次你可以选中一个 \([ 1 , N]\) 中还在黑板上的整数 \(x\),把它擦去并补写上 \(x − 2\)\(x + K\)(如果原来不存在的话)。你可以进行这个操作任意次(可以不进行),求最终黑板上数字的可能状态有多少种,答案对 \(M\) 取模。

    \(1\leq K \leq N \leq 150 , 10^8\leq M\leq 10^9\)


    又是猜对了结论但是不会维护。

    首先结论是:

    对于每个点 \(x\),向 \(x - 2, x + K\) 连边,我们取出所有删去的点的导出子图,这个图必须是一个 \(\rm DAG\) 才是合法的。

    连边是钦定 \(x - 2, x + K\)\(x\) 后面删掉,只要不出现环形依赖就不会有问题。

    考虑计数,对于 \(K\) 为偶数,我们就是可以奇偶分别考虑,要求不能形成 \(\frac{K}{2} + 1\) 个同时被擦除的元素即可。

    对于奇数,蒯张图,(\(n = 12, K = 3\))我们考虑出现的环的状况(对于奇数,将 \(i, i + K\) 放在一起):

    对于一个环,一定是从 \(a\) 出发,向上走若干步,然后向右走若干步,再向上走若干步,最后回来。(例如 \(9 \to 7 \to 5 \to 8 \to 6 \to 9\)

    考虑一层一层地 DP,设 \(f(i, j, k)\) 表示到了第 \(i\) 层,(我们把 \(x, x +K\) 的数当做一层,然后这个 DP 要预处理前面单着的数)从当前左部点出发最长可以走的路是 \(j\)(向上走若干步,然后向右走若干步,再向上走若干步 的长度),右边最长连续的长度为 \(k\)(方便 \(j\) 的转移)。

    转移的时候讨论即可,具体看代码的注释。 ↩︎

  4. AGC017F Zigzag

    • 给定一个 \(N\) 层的三角形图,第 \(i\) 层有 \(i\) 个节点。
    • \(i\) 层的节点,从左到右依次标号为 \((i, 1), (i, 2), \ldots , (i, i)\)(具体如上图所示)。
    • 你需要从 \((1, 1)\) 往下画 \(M\) 条折线。
    • 对于每条折线的每一个小段,你可以从 \((i, j)\) 画到 \((i + 1, j)\) 或者 \((i + 1, j + 1)\)
    • 同时你还必须保证第 \(i\) 条折线的任何一个位置必须不能处在第 \(i - 1\) 条折线的左侧,它们必须按照从左到右的顺序排列。
    • \(K\) 条限制,每条限制形如 \((A_i, B_i, C_i)\)
    • 表示第 \(A_i\) 条折线处于位置 \((B_i, j)\) 时,下一小段必须走向 \((B_i + 1, j + C_i)\),也就是当 \(C_i = 0\) 时向左,当 \(C_i = 1\) 时向右。
    • 询问不同的折线画法的方案数,对 \({10}^9 + 7\) 取模。
    • \(1 \le N, M \le 20\)\(0 \le K \le M (N - 1)\)。其它变量在合理范围内。

    如果一层一层地决策进行状压 DP,那么就是 \(\mathcal O(4^n n)\) 的。但是我们可以试着转换一下计数顺序!于是考虑一条一条线段分配位置!

    我们把上次的线段的路线记作一个二进制数,如果第 \(i\) 位为 \(1\),那么就代表在 \(i\) 层的时候向右走了。

    当前这一条的线段的方案只要倒着前缀和的字典序 \(\ge\) 上一条的即可(因为最初一步为最低位,因此略有不同),如果暴力地 DP,还是 \(\mathcal O(4^nn)\),但是转移到了 \(\mathcal O(1)\) 了!

    我们接着可以发现,如果完全暴力地 DP,很多信息没有利用到,如果我们决策这一条线的路线的时候考虑一层一层地计算呢?可以发现,我们不能很好地处理字典序的问题,然后可以发现我们可以直接记录我们之后可以选择的范围!

    具体地,我们要枚举第 \(i\) 层,以及上一次决策导致的我们可以选择范围的状态为 \(s\),记 \(s\) 的第 \(i\) 位为 \(s[i]\),如果:

    • 如果我们这一层选择走左边 \(0\),只要 \(s[i] = 0\) 即可,然后转移到 \(s\)

    • 如果我们走右边 \(1\)

      • 如果 \(s[i] = 1\),那么可选范围还是 \(s\),两个重合了。
      • 如果 \(s[i] = 0\),那么意味着我们一直到 \(i\) 下一个 \(1\) 处都可以选择 \(0\),于是把 \(s\)\(i\) 位置后面的第一个 \(1\) 设为 \(0\),然后把 \(s[i]\) 设为 \(1\),就是新的可选范围了!
    ↩︎
  5. AGC025E Walking on a Tree/ 校内考试 6.7 疯狂路径(path)

    给定一棵 \(n\) 个节点的树和 \(m\) 条树上的路径,要求为每一条路径定向。

    \(i\) 条树边 \((a_i, b_i)\) 的权值为满足下述条件的条数:

    • 被某条路径沿 \(a_i\to b_i\) 方向经过。
    • 被某条路径沿 \(b_i\to a_i\) 方向经过。

    求最大权值和并给出 \(m\) 条路经的定向方案,多组方案合法输出任意一组即可。

    \(n,m\leqslant 2000\)。加强:\(n, m \le 1 \times 10^5\)


    一个比较有意思的结论题。

    考虑答案的上界,一定是 \(\sum \min\{每条边覆盖次数, 2\}\),考虑达到上界:

    每次选出一个叶子,然后考虑所有以它开始的路径,如果没有则不管,只有一条,则如何选择结果不变,将这个路径放到它父亲上面皆可;如果有两条以上,任意选择两条,这两条路径的方向一定是相反的,设路径为 \((u, a), (u, b)\),我们新建一条路径 \((a, b)\),删去这两条路径,并将其他路径放到父亲上去决策,然后根据 \((a, b)\) 的情况,如果 \((a, b)\) 不反向,那么 \((u, a)\) 反向,\((u, b)\) 不反向,反之亦然。

    为什么可以新建这条路径呢?因为这样 \((u, a), (u, b)\)\((a, b)\) 不相交的部分是不重要的,怎么样都是合法,我们只关心 \((a, b)\) 路径,同时这样可不会影响其他叶子的状态。

    这个是一个比较暴力的构造,时间复杂度为 \(\mathcal O(n^2)\),考虑优化:

    首先反向关系的继承可以通过带权并查集完成,我们的复杂度瓶颈在于怎么将边给传上去,这个可以通过链表完成。

    然后细节有亿点多,至少用了大半个下午肉眼盯傻了,但是上了对拍就可以发现很多问题!

    一些细节:

    • 判断取出来的边是否合法。
    • 颜色关系的继承可能要自己在纸上面多画画。
    • 注意取出来的对应的 \((u, a)\) 中的 \(a\) 可能已经被删了,我们要用并查集找到最近的祖先。
    • 注意处理边的反向情况,可以通过一些特判 / 丢进去的时候顺便压缩方向。

    可以看看代码 Atcoder/problems/AGC025E.cpp · yinjinrun/code-public-2 - 码云 - 开源中国 (gitee.com)


    上面的过于繁琐!考虑更加简单的做法!

    我们对于每条路径 \((u, v)\) 连一条无向边,接着考虑从叶子推到根,如果该点的度数为奇数,就让父亲和它连无向边,这样建出图来跑欧拉回路,就可以构造出方案了!大概是这样的建图会使每一条后面补充的边的两种覆盖方向的差 \(\le 1\),于是可以满足条件。 ↩︎

  6. AGC052D Equal LIS

    给出一个 \(n\) 阶排列 \(\{P_i\}\),你要将其分成两个子序列 \(\{a\} \{b\}\),满足其 \(\rm LIS\) 相等。

    \(n \le 2\times 10^5\),多测。


    \(f_i\) 表示以 \(i\) 结尾的最长上升子序列,\(L = \max\{f_i\}\)

    如果 \(2 \mid L\),那么将令 \(a = \{i | f_i \le \frac{L}{2}\}, b = \{i | f_i > \frac{L}{2}\}\),易知满足条件。

    如果 \(2 \nmid L\),令 \(L = 2k + 1\),我们怎么分,两个子序列的 \(\rm LIS\) 最大至少都是 \(k +1\),于是我们可以构造两个 \(k + 1\)\(\rm LIS\)

    如果对于一个长度为 \(L\)\(\rm LIS\),存在一个不在该 \(\rm LIS\) 中的元素 \(x\),满足一个长度为 \(k+1\)\(\rm LIS\) 包含 \(x\),那么就是有解的。

    必要性是比较显然的,至于充分性,可以通过构造来说明:

    令这个包含 \(x\) 的长度为 \(k +1\)\(\rm LIS\)\(p_1, p_2, \dots, p_{k + 1}\),那么 \(a = \{i | f_i \neq f_{p_j}\vee (f_i = f_x \wedge i \neq x) \}, b = P / a\),我们就会发现对于每个集合,里面 \(f_i\) 不同的个数之多为 \(k + 1\),于是两个集合的 \(\rm LIS\) 都是 \(\le k + 1\) 的,对于 \(a\),原来的长度为 \(L\)\(\rm LIS\) 中有 \(k\) 个不能选择,长度至少是 \(k + 1\),而对于 \(b\),至少有一个 \(p_1, p_2, \dots, p_{k + 1}\) 在里面于是也是 \(k + 1\) 的。

    可以通过树状数组处理出 \(f_i\) 以及以 \(i\) 开头的 \(\rm LIS\) 长度 \(g_i\) 完成统计。 ↩︎

  7. AGC003E Sequential operations on Sequence

    一串数,初始为 \(1\sim n\),现在给 \(Q\) 个操作,每次操作把数组长度变为 \(q_i\),新增的数为上一个操作后的数组的重复。问 \(Q\) 次操作后 \(1\sim n\) 每个数出现了多少次。

    \(n, Q \le 10^5, q_i \le 10^{18}\)


    居然没有想到第一步/kk!只要第一步会了,之后就比较 easy 了!

    如果 \(q_i \le q_{i - 1}\),那么 \(q_{i - 1}\) 就是没有用的,于是可以直接删除!

    然后 \(q\) 就是递增的了,这时一个非常优美的性质!

    我们只要求出 \(cnt_i\) 表示第 \(i\) 次操作后留下的序列会对答案产生多少影响,然后一步一步往前推即可,最开始最后的 \(cnt = 1\)

    每次我们要计算当前 \(i\) 号数组对于答案的贡献为 \(t\),那么就是 \(\left\lfloor\frac{a_i}{a_{i - 1}}\right\rfloor\)\(i - 1\) 号数组,以及 \(a_i \bmod a_{i - 1}\)\(i - 1\) 前面的元素,这个可以找到最后一个 \(\le a_i \bmod a_{i - 1}\),然后递归处理,处理到初始状态就是一个前缀的答案,直接差分处理,因为每次取模大小至少会砍半,于是复杂度是 \(\mathcal O(q \log q)\) 的。 ↩︎

  8. AGC006C Rabbit Exercise

    有 $n $ 只兔子在一个数轴上,兔子为了方便起见从 \(1\)\(n\) 标号,第 \(i\) 只兔子的初始坐标为 \(x_i\)

    兔子会以以下的方式在数轴上锻炼:一轮包含 \(m\) 个跳跃,第 \(j\) 个是兔子\(a[j]\) (\(2\le a[j]\le n−1\)\(\{a\}\) 是给出的长度为 \(m\) 的数组) 跳一下,这一下从 兔子 \(a[j]− 1\) 和 兔子 \(a[j] + 1\) 中等概率的选一个(假设选了 \(x\)),那么 \(a[j]\) 号兔子 会跳到它当前坐标关于 \(x\) 的坐标的对称点。(注意,即使兔子的位置顺序变化了,但是编号仍保持不变,这里按兔子编号算)兔子会进行 \(k\) 轮跳跃,对每个兔子,请你求出它最后坐标的期望值。

    \(1 \le n \le 10^5, 1 \le m \le 10^5, k \le 10^{18}\)


    之前的考试题,补一发题解。

    首先,这个概率比较离谱,但是有一个非常好的性质,假设操作元素为 \(Y\),前一个为 \(X\),后一个为 \(Z\),那么 \(E'(Y) = \frac{2E(X) - E(Y) + 2E(Z) - E(y)}{2} = E(X) + E(Z) - E(Y)\),根据这个可以做到暴力 \(\mathcal O(mk)\)

    然后考虑原来期望序列的差分,我们可以发现每次是交换两个元素,于是可以直接倍增维护这个期望序列,复杂度 \(\mathcal O(n \log k)\)

    感觉题目难点在于发现期望的变化规律…… ↩︎

  9. AGC007D Shik and Game

    Shik 君在玩一个游戏。

    初始时他在数轴的 \(0\) 位置,出口在 \(E\) 位置,并且数轴上还有 \(n\) 只小熊,第 \(i\) 只小熊在 \(x_i\) 位置。

    Shik 君拿着 \(n\) 块糖果出发,每走一个单位长度要花费一秒。到一个小熊的位置时,他可以送给这个小熊一块糖果,这个过程不花时间。小熊收到糖果后,\(T\) 秒以后会在它所在的位置产生一个金币。

    Shik 君想知道,他从出发到收集了所有金币抵达出口,最少要花费多长时间。

    \(n \le 10^5\)


    AGC 也有板子题/惊讶。

    首先,肯定是将整个序列划分成一段一段,每个人每次走到一段的尽头,然后回来,因此对于这个考虑 DP。

    \(E\) 的长度一定要走,于是我们姑且不看,只计算增量,最后将答案 \(+E\)

    \(f(x)\) 表示只考虑前 \(x\) 的最小增量。

    如果暴力就是枚举 \(y \le x\),表示将 \(y \to x\) 都划分为一段,那么有 \(f(x) = \min_y \{f(y - 1) +\max\{T, 2\mathrm{dis}(x, y)\} \}\),画画图不难发现是对的。

    首先这个 DP 有单调性,如果后面的 \(\max\)\(T\),那么就应该选择最前面的元素,如果是 \(2\mathrm{dis}\),那么可以直接通过前缀和处理出来。因此只要二分分界点即可进行 DP。 ↩︎

  10. AGC007E Shik and Travel

    一颗 \(n\) 个节点的二叉树,每个节点要么有两个儿子要么没有儿子,边有边权。

    你从 \(1\) 号节点出发,走到一个叶子节点。然后每一天,你可以从当前点走到另一个叶子。最后回到 \(1\) 号节点,要求到过所有叶子并且每条边经过恰好两次

    每天的路费是你走过的路径上的边权和,你的公司会为你报销大部分路费,除了你旅行中所用路费最高的,行走路线是从叶子到叶子的那一天的路费。

    求你自己最少要付多少路费?

    \(2 \le n, a_i, v_i \le 131072\)


    好题,启发了启发式合并的变种!(只能说大概比较像了)

    不难发现,肯定要二分答案,转化为判定问题。

    然后每个节点有一个属性,进去这个子树的长度以及出来这个子树的长度,然后我们要考虑如何将其儿子合并,这里是没有办法贪心的,只能 DP,然后状态数是 \(\mathcal O(n^2)\) 的,比较棘手。

    这个时候可以发现,如果 \((x, y),(a, b)\) 满足 \(x \le a \wedge y \le b\),那么 \((a, b)\) 是没有用的,于是我们可以将 \((a, b)\) 删除。

    加速合并可以直接双指针,然后我们发现这个时候复杂度正确了!

    为什么呢?

    考虑状态大小为 \(x\)\(y\) 的两个点合并,那么新状态会变成 \(\min\{x, y\}\),这个至少会将状态数目减半,初始状态 \(\mathcal O(n)\),因此总共复杂度不会超过 \(\mathcal O(n)\),因为合并完了要排序去重,复杂度不超过 \(\mathcal O(n \log n)\),加上二分是 \(\mathcal O(n\log^2n)\) 的。 ↩︎

posted @ 2022-06-13 21:28  Werner_Yin  阅读(135)  评论(0编辑  收藏  举报