AGC 做题合集 #5

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

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

  1. AGC018D Tree and Hamilton Path

    有一颗 N 个顶点的树,顶点依次标号 1N

    i 条边连接着顶点AiBi,且第 i 条边的长度为 Ci

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

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

    2n105


    WA 了 发后终于猜对了结论!

    首先,我们令第 i 条边 (xi,yi,wi) 中的 yi 为深度更大的点,可以猜测上界为 L=i2min{nsizy,sizy}wi,然后手玩样例可以发现,这个上界在哈密顿回路下面是成立的,于是我们只要确定起点终点 (a,b),然后答案就是 Ldis(a,b)

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

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

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

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

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

  2. AGC014D Black and White Tree

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

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

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

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

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

    2N105


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

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

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


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

  3. AGC013C Ants on a Circle

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

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

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

    1N105,1L109


    这个题比较妙妙妙啊。

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

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

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

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

  4. AGC028C Min Cost Cycle

    • 给定一个 n 边的有向完全图,每个点有两个点权 ab,一条边 (u,v) 的边权值的计算方法为 min(au,bv)
    • 求边权和最小的哈密顿回路的边权和。
    • 对于 100% 的数据,2n1051a,b109

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

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

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

    • 全部是 A。
    • 全部是 B。
    • 存在一个 i 满足,ai,bi 都没有标记。

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

  5. AGC028B Removing Blocks

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

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

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

    1N105

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

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

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

    然后一直想着 DP

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

    显然,设 d=yx+1,那么方案数就是 (nd)(nd)!(d1)!,注意到这个式子只和 d 有关,于是枚举 d 即可计算。 ↩︎

  6. AGC028D Chords

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

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

    1n300


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

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

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

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

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

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

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

    于是 f(l,r)=g(cnt(l,r))i=lr1f(l,i)g(cnt(i+1,r)),直接区间 DP 即可,复杂度 O(n3)↩︎

  7. AGC016D XOR Replace

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

    1n105


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

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

    令异或和为 val,那么可以达到目标的充要条件就是 (val{ai}){bi}

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

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

  8. AGC016E Poor Turkeys

    N(2N400) 只火鸡,编号为 1N,有 M(1M105) 个人,每人指定了两只火鸡 xy

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

    注意,第 1 个人到第 M 个人每个人依次行动。求有多少个 (i,j)(1i<jN) 满足在最终时刻第 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<v1,2号点各一个石头,每次可以沿DAG上的边移动一颗石头,不能移动则输,求所有2m个边的子集中,只保留这个子集先手必胜的方案个数。

    n15,mn2/2


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

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

    • 对于 SGx 的点的集合,我们记为 Sx
    • Sx 内部不能有边。
    • y<xSx 中的每个点必须要向 Sy 中的至少一个点连边。
    • 对于 y>xSx 中的每个点向 Sy 中点连边的情况是任意的。

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

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

  10. AGC032D Rotation Sort

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


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

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

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

posted @   Werner_Yin  阅读(102)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示