AGC 做题合集 #9

  终于到了 #9 了呢,每每 rand 到这首歌,我总有一种“退役的你”的既视感,但这次,是真的近了。

  1. "AGC028F Reachable Cells"[1] 加强版真正的做法等学会了一定来补。
  2. "AGC028E High Elements"[2]
  3. "AGC006D Median Pyramid Hard"[3]
  4. "AGC007F Shik and Copying String"[4]
  5. "AGC020D Min Max Repetition"[5]
  6. "AGC012D Colorful Balls"[6]
  7. (VP)"AGC047C Product Modulo"[7]
  8. (VP 非严格补题)"AGC047D Twin Binary Trees"[8]
  9. "AGC038F Two Permutations"[9]
  10. (VP 补题)"AGC047E Product Simulation"[10]

  1. AGC028F Reachable Cells

    给定一张 \(N\)\(N\)列的网格图,每一个格子有两种情况:有障碍物,或者是空的并且写着一个 \(1\sim 9\)的整数。

    称格子 \(Y\)能被格子 \(X\)到达当且仅当以下条件均被满足:

    • 单元格 \(X\)\(Y\)不同。
    • 单元格 \(X\)\(Y\)均为空。
    • 通过反复向右或向下移动到相邻的空单元格,可以从单元格 \(X\)到达单元格 \(Y\)

    求出 \(\sum A_XA_Y\),其中 \(X\)可以到达 \(Y\),A代表格子上的数。

    \(N \le 500\),加强版 \(N \le 1500\)


    我们可以从下到上,从右到左计算答案,同时维护 \(L_{i, j, k},R_{i, j, k}\) 表示从 \((i,j)\) 出发,到达 \(k\) 行的最左边可以到达的列,最右边到达的列是什么。

    同时对于每一行维护前缀和,然后就可以算出答案了。但是显然这个是不正确的,因为存在一些点完全被挡住了,比如对于样例:

    4
    1111
    11#1
    1#11
    1111
    

    我们发现 \((1, 1)\) 在第 \(3\) 行的 \(L\)\(R\)\(1,4\),但是 \((3, 3)\) 是到不了的。

    于是我们要考虑删掉 \((3, 3)\) 这种格子。

    对于一个格子\((x, y)\),如果 \((x - 1, y),(x, y - 1)\) 都是障碍,同时它不是障碍,我们就令它为障碍,然后更新前缀和,接着会出发一串连锁反应,一堆格子会成为障碍,只要不断 DFS 即可。

    然后我们发现所有不能到的格子已经删除干净了。

    复杂度 \(\mathcal O(n^3)\),然后 \(f_{i, j, k}\) 中的 \(i\) 可以通过滚动数组压掉,空间复杂度 \(\mathcal O(n^2)\)。加强版可以通过这个卡常后艹过。

    至于卡常,可以看 feecle6418 的题解,这里不再赘述,不过不用全部用,比较关键的是指针二维数组、交换前缀和数组顺序和手写递归栈。 ↩︎

  2. AGC028E High Elements

    你有一个\(1,2,\dots,n\) 的排列 \(P\)。设一个长度为 \(n\)\(01\) 字符串 \(S\) 合法,当且仅当,先设两个空序列 \(A,B\),我们按照 \(1\)\(n\) 的顺序,若 \(S\) 当前位为 \(1\) 则把当前位的 \(P\) 添加到序列 \(A\) 的末尾,否则添加到序列 \(B\) 的末尾,使得 \(A,B\) 的前缀最大值个数相等。求字典序最小的合法字符串 \(S\)

    数据范围:\(n\le 2\times 10^5\)\(P\)\(1,2,\dots,n\) 的排列。


    金牌神仙题啊。

    对于字典序最小,显然可以变成按位贪心,然后问这里填了 \(0\) 之后是否还能合法,转化为判定性问题。

    我们记“原来的”表示 P 的前缀最大值,“新增的”表示非原来的但是成为了 \(A/B\) 中间的前缀最大值。

    一个比较神仙的结论:

    考虑“新增的”前缀最大值位于那个序列,一定存在一种方案使得新增的都位于 \(A\) 或者都位于 \(B\)

    证明:

    如果 \(A\) 中有一个新增的,\(B\) 中有一个新增的,同时方案合法。

    我们将 A 中的放到 B,B 中的放到 A,那么这两个元素都不是前缀最大值了,然后方案依然合法。

    不断操作,直到一个变成 \(0\) 即可。

    假设 \(A\) 中没有新增的元素。同时目前我们 A 的前缀最大值个数为 \(mx\),B 的前缀最大值个数为 \(my\),剩下的序列中“原来的”个数为 \(cnt\),而我们找到一种方案,使得分配给 B 的“原来的”个数为 \(cy\),B 中新增的元素个数为 \(k\)

    有等式:

    \[mx + cnt - cy = my + cy + k\\ mx + cnt - my = 2cy +k \]

    左边的为定制,剩下的问题就是,我们把原来的元素权值当作 2,新增的元素的权值当作 1,是否存在一种方案使得权值为左边。

    同时,对于一种权值为 \(t\) 的选择方案,我们可以不断删除原来的元素,使得权值为 \(t - 2v\),于是只要对于权值分开奇偶考虑最大值即可。

    可以使用 DP + 线段树维护(类似 \(\rm LIS\) 的过程),维护以 \(x\) 结尾的方案的权值为奇/偶的最大值。 ↩︎

  3. AGC006D Median Pyramid Hard

    给出一个 \(N\) 层的方格金字塔,自顶向下依次标号为第 \(1\) 到第 \(N\) 层。

    其中第 \(i\)(\(1 \le i \le N\))层有 \(2i − 1\) 个方格。

    \(N\) 层有一个 \(1\)\(2N-1\) 的排列,其他层的数字按以下规则生成:方格 \(b\) 中填写的整数,是方格 \(b\) 正下方,左下方和右下方方格中所写整数的中位数。

    现在给出第 \(N\) 层的数字,请你求第一层的数字。

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


    很早之前做过的,补一发题解。

    首先,不难想到二分答案,于是只要考虑一个 \(01\) 串最后的状况了。

    通过手玩可以发现,在底层距离中心点最近的连续两个相同的数字会一直上升,直到到了顶端,因为只有两种数字,因此这个位置一定是唯一的(或者不存在)。

    特判不存在这种相邻的两个数相同的情况即可。 ↩︎

  4. AGC007F Shik and Copying String

    Shikk 的工作是复制。有一天,Shikk 从他的上司那里拿到了一个由小写英文字母组成的长度为 \(N\) 的字符串 \(S_{0}\)(假设这天是第 \(0\) 天)。这之后第 \(i\) 天的工作是把 \(S_{i-1}\) 复制到 \(S_{i}\)。下文中的 \(S_{i}[j]\) 表示字符串 \(S_{i}\) 的第 \(j\) 个字母。

    Shikk 还不怎么习惯这个工作。每天,当 Shikk 从第一个字母开始按顺序复制字符串时,他有可能会写下和刚刚写下的字母相同的字母,而不是本来应该写下的字母。也就是说,\(S_{i}[j]\) 要么与 \(S_{i-1}[j]\) 相同,要么与 \(S_{i}[j-1]\) 相同。(特别地,字符串开头的字母不可能出错。也就是说,\(S_{i}[1]\) 必然与 \(S_{i-1}[1]\) 相同。)

    输入两个字符串 \(S_{0}\)\(T\),请求出使得 \(S_{i}\) 有可能与 \(T\) 相同的最小的整数 \(i\)。如果这样的 \(i\) 不存在,请输出“-1”。


    做出银牌题了!ヾ(๑╹◡╹)ノ" 不过不完全是独立做出来的,虽然没看题解但是下了个数据找叉点。

    首先,正着麻烦,考虑倒着整。

    我们可以仔细观察一下变化的形式,将序列划分为连续段的形式,每一段提取第一个点作为标志点,那么我们就有一个标志点序列 \(p_1, p_2, \dots, p_k\),表示 \(p_1 \sim p_2 - 1\) 是一个字符,\(p_2 \sim p_3 - 1\) 是一个字符……

    记一次操作后的标志点序列为 \(p'\),那么有 \(p'_{i} \in [p_{i - 1} + 1, p_{i}]\),同时我们考虑什么时候会结束,目前我们每个标志点上面的字符和 \(s\) 对应位置字符相同!这样只要一步就是 \(s\) 了。比如这样:

    s = abcde
    t = aaccc
    p = 1,3
    

    转化一下问题,我们现在有一个序列 \(p_1, p_2, \dots, p_k(1 = p_1 < p_2 < \dots \le n)\),我们需要求一个类似于匹配的序列 \(t = \{t_1, t_2, \dots, t_k\}(1 = t_1 < t_2 < \dots \le n, t_i \le p_i, T[p_i] = S_0[t_i])\),然后最小化操作次数使得 \(p \to t\)

    两个问题,求序列 \(t\),最小化次数。

    求序列 \(t\),我们注意到 \(t\) 中每个元素越后越好,于是从 \(k \to 1\) 考虑,贪心找到最后的满足条件的元素,这个随便维护。


    最小化次数,我开始 WA 的几发就是这里寄了。

    考虑每次变化后序列是 \(p'_{i} \in [p_{i - 1} + 1, p_{i}]\),这个是一个区间,因为我们可以停止在某个地方(比如到了 \(t_i\)),就比较烦,于是直接考虑我们在 \(x\) 次操作后 \(p_i\) 的最小值 \(\min\{p_{x, i}\}\),显然就是每个元素一直变成 \(p_{i - 1}+1\),于是有 \(\min\{p_{x, i}\} = p_{i - x} + x\),有 \(p_{x, i} \in [p_{i - x} + x, p_i]\),于是可以二分每个元素到目标位置的最少次数,复杂度 \(\mathcal O(n\log n)\)

    代码


    看了看题解,发现大家做法都很神秘,而且还是 \(\mathcal O(n)\)!然后发现完全不要二分这种玩意儿,直接暴力更新答案即可。

    代码

    不过也没快多少↩︎

  5. AGC020D Min Max Repetition

    多组询问。每个询问给定四个整数,\(A,B,C,D\),求一个满足这个条件的字符串:

    1. 长度为 \(A+B\),由 \(A\) 个字符 A 和·\(B\) 个字符 B 构成。
    2. 在此基础上,连续的相同字符个数的最大值最小。
    3. 在此基础上,字典序最小。

    输出这个字符串的第 \(C\) 位到第 \(D\) 位。

    \(1 \le Q \le 10^3, 1 \le A, B \le 5 \times 10^8, 1 \le C \le D \le A+B, D - C + 1 \le 100\)


    感觉是大分类讨论,于是弃疗了,点开题解,发现是二分/kk。

    首先,连续的相同字符个数最大值最小为 \(K= \left\lfloor\frac{\max\{A,B\}}{\min\{A,B\} + 1}\right\rfloor\)

    因为字典序最小,于是可以发现最后的答案一定是 \(\overbrace{A\dots A}^{K}B\overbrace{ A \dots A}^{K}B \dots \overbrace{A \dots A}^{t \in [1, K]}\) 的一个前缀和 \(A\overbrace{B\dots B}^{t \in [1, K]}A\overbrace{ B \dots B}^{K}A \dots \overbrace{B \dots B}^{K}\) 一个后缀组成,同时,要么就是这个前缀 / 后缀不存在,要么就是后缀和前缀共用一个 \(A\)

    显然,我们是希望这个前缀尽可能长,而在前缀尽可能长的情况下,对于剩下的 \(A\) 个数 \(a\) 以及剩下的 \(B\) 个数 \(b\) 满足 \(b \le Ka\) 即可。

    显然这个条件有单调性,于是可以二分前缀的长度,由于前面说的前后缀的关系,一定会让前缀结尾的时候是 \(A\)(或者前缀长度为空)。 ↩︎

  6. AGC012D Colorful Balls

    \(N\) 个球排成一排,第 \(i\) 个球的颜色为 \(c_i\),重量为 \(w_i\)。我们定义「一次操作」为:选择两个颜色相同,且重量之和不超过 \(X\) 的球,交换它们的位置;或选择两个颜色不同,且重量之和不超过 \(Y\) 的球,交换它们的位置。问进行任意次操作后,可以得到多少种不同的颜色序列。输出答案对 \(10^9+7\) 取模的结果。

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


    这个差了非常小的一点就是独立做出来了!开始写了个做法 WA 了 16 个点,卡了半天比较自闭,后来瞟了一眼题解发现“只要组合数”,然后自己的做法便是只有组合数!于是改了改就对了。

    首先,我们可以想到,一种颜色的球中间,只要最小的能换动另一个球,那么大一点的球的位置便非常自由,于是只要关心最小的球能不能换动。

    将球根据一下两个条件分为 \(4\) 种:

    1. 该颜色的最小的球能否换动它。
    2. 其他颜色最小的球能否换动它。

    如果满足 \(2\),那么我们就定义这种求是超级自由的球!如果只满足 \(1\),那么我们定义为相对自由的球,否则我们可以直接删去这个球,它不会对答案造成任何影响,只能在原来的位置上。

    而最后一个样例就是所有球都是超级自由的。这种情况答案就是所有超级自由的球任意排列所产生的颜色序列的方案数(因为每个球都有一个球可以换动它,然后所有球位置都在可以的范围内任意移动),简单多重排即可。

    之后就对于性质(粗体部分)的发掘不是非常深入,导致对于相对自由的球的处理不是很对。

    粗体部分的描述非常不直观,我们应该如何描述呢?观察策略,我们可以发现交换的关系具有可传递性!如果两个球可以被移动,那么连一条边,对于之后形成的图,每一个连通块内元素位置都是可以排列的!

    对于原图考虑,我们发现这样建图后,最多只有一个连通块满足球的颜色 \(\ge 2\),于是:

    对于一种颜色的球(只有相对自由和超级自由的球了),如果存在一个超级自由的球,那么这种球都是超级自由的!否则就直接删去(换来换去,颜色还是没有变化)。

    最后就是所有超级自由的球的方案数了。 ↩︎

  7. AGC047C Product Modulo

    给定 \(P = 200003\),已经 \(N\) 个整数 \(A_1, \dots, A_N\),求 \(\sum_{i < j} (A_iA_j \bmod P)\),注意,求和的时候不取模。

    \(2 \le N \le 200000\)


    VP 的时候因为 SB 错误 WA 了 \(\infty\) 发一个点……直接导致后面的 D 没有时间了。

    对于乘法然后取模,经典的是直接算出原根,然后转为加法操作。

    之后就是求 \(f_i = \sum_{j + k \bmod (P - 1) = i} cnt_j cnt_k\) 了,直接卷积即可。

    可以使用 FFT 解决,当然,我开始脑抽了,使用了 NTT,因为会溢出 \(998244353\),于是可以采用类似于根号分治状物,当 \(cnt_i \ge 60\) 的时候暴力和其他元素算贡献,否则交给 NTT。 ↩︎

  8. AGC047D Twin Binary Trees

    给定两棵高为 \(H\) 的二叉树,一条路径权值为其上面的点的编号之积。

    给定一个长为 \(2^{H - 1}\) 的排列,对于 \(p_i = j\),表示第一棵树的 \(i + 2^{H - 1} - 1\) 和第二棵树的 \(j + 2^{H - 1}-1\) 有一条特殊边。

    求所有经过至少两条特殊边的路径权值之和。

    \(H \le 18\)


    给我 \(15\) 分钟,我一定可以切了这个 D!

    枚举第一棵树的 \(\rm LCA\),然后每条路径 \((x, y)\) 的权值就是两个数之积形式,然后把所有点放到第二棵树上面,建立虚树,然后在上面 DP(也是枚举 \(\rm LCA\) 状物)。

    最后可能算重,于是可以类似点分治一样再整一个容斥即可。 ↩︎

  9. AGC038F Two Permutations

    给定两个 \(0 \sim (N - 1)\) 的排列 \(\{P_0, P_1, \ldots , P_{N - 1}\}\)\(\{Q_0, Q_1, \ldots , Q_{N - 1}\}\)

    要求构造两个 \(0 \sim (N - 1)\) 的排列 \(\{A_0, A_1, \ldots , A_{N - 1}\}\)\(\{B_0, B_1, \ldots , B_{N - 1}\}\)

    且必须满足条件:

    • \(A_i\) 要么等于 \(i\),要么等于 \(P_i\)
    • \(B_i\) 要么等于 \(i\),要么等于 \(Q_i\)

    你需要最大化 \(A_i \ne B_i\) 的下标 \(i\) 的数量,输出这个最大值。

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


    讲课题,写发题解。

    一个比较关键的结论是:

    对于 \(P\)\(A\)(对于 \(Q\)\(B\) 类似)我们考虑一个置换环,不妨假设是 \((1, 2, \dots, k)\),考虑 \(A_1\) 是什么,如果是 \(1\),那么我们可以推出 \(P_i = i\),如果是 \(2\),我们可以推出 \(P_i = i + 1\)。也就是一个置换环的状态是绑在一起的,分为拆和不拆两种。

    分类讨论所有 P,Q 的情况:

    • \(P_i \neq i, Q_i \neq i\)

      • \(P_i \neq Q_i\):如果 \(P_i\)\(Q_i\) 所在置换环都不拆,就会有一的代价。
      • \(P_i = Q_i\):如果 \(P_i\)\(Q_i\) 所在置换环都不拆 或者 都拆,就会有一的代价。
    • \(P_i \neq i \vee Q_i \neq i\)

      • \(P_i = i\),如果 \(Q_i\) 所在置换环不拆,那么会有一的代价。
      • \(Q_i = i\),如果 \(P_i\) 所在置换环不拆,那么会有一的代价。
    • \(P_i = Q_i = i\):没救了,直接增加一的代价。

    这个问题和网络流的最大权闭合子图(文理分科模型)非常像,但是我们可以回顾一下文理分科适用于什么情况:

    对于一个集合,如果这个集合里面的点如果存在一个点不选,那么会付出什么代价;如果存在一个点选,会付出什么代价;一个点选了,另外一些点也有选了,就会付出什么代价;一个点不选,另外一些点也不选,就会付出什么代价

    如果条件取反,也可以一个集合点全选或者全不选的收益(先加上,然后转为上面的限制)。

    这种模型中,我们只能根据状态的或(或者一个状态取反后的或,但是必须要存在没有取反或者取反的点)来制定代价,而这个题目让我们根据状态的与(或者变量同时取反的与)制定代价。存在一定不同。

    如果我们直接使用上面的模型,会发现建图有点困难。

    但是我们可以发现,我们所有二元变量之间的关系构成了一张二分图,于是我们可以通过取反一部分状态的定义使得上面的模型成立

    建立 \(S,T\),以及一个二分图,如果 \(S\)\(P\) 部点相连,那么代表 \(P\) 这个环不拆,如果 \(T\)\(Q\) 部点相连,那么代表 \(Q\) 这个环不拆。

    有建图(其中 \(L(P_i)\) 表示 \(i\) 号点在 \(P\) 中置换环代表的点,另一个类似):

    • \(P_i \neq i, Q_i \neq i\)

      • \(P_i \neq Q_i\):如果 \(P_i\)\(Q_i\) 所在置换环都不拆,就会有一的代价 \(\Rightarrow\) \((R(Q_i),L(P_i), 1)\)
      • \(P_i = Q_i\):如果 \(P_i\)\(Q_i\) 所在置换环都不拆 或者 都拆,就会有一的代价 \(\Rightarrow\) \((R(Q_i),L(P_i), 1)\)\((L(P_i),R(Q_i), 1)\)
    • \(P_i \neq i \vee Q_i \neq i\)

      • \(P_i = i\),如果 \(Q_i\) 所在置换环不拆,那么会有一的代价 \(\Rightarrow\) \((S, R(Q_i), 1)\)
      • \(Q_i = i\),如果 \(P_i\) 所在置换环不拆,那么会有一的代价 \(\Rightarrow\) \((L(P_i), T, 1)\)
    • \(P_i = Q_i = i\):没救了,直接增加一的代价。

    求最小割即可。 ↩︎

  10. AGC047E Product Simulation

    这是一个提交答案题。

    现在有 \(N + 1\) 个位置 \(a\),编号为 \(0 \sim N\),其中 \(a[0] = A, a[1] = B\),你要通过以下操作使得 \(a[2] = A\times B\)

    • + i j k\(a[k] = a[i] +a[j]\)
    • < i j k\(a[k] = a[i] < a[j]\)

    操作次数 \(\le Q\)

    \(N = Q = 200000, 0 \le A, B \le 10^9\)


    大体思路是看了题解的,其中使用函数化(一个黑盒)进行构造会节省很多时间!

    总体就是题解中最后的伪代码:

    for(int k = 58; k >= 0; k–) {
        answer *= 2;
        for(int i = 0; i <= k; i++){
            int j = k - i;
            if(i < 30 && j < 30) {
                answer += 1<(a_bits[i]+b_bits[j]);
            }
        }
    }
    

    只要解决几个比较重要的问题:

    1 从哪里来

    因为 \(A= B = 0\) 答案为 \(0\),可以不考虑此情况。

    那么可以计算 \(0 < (A+B)\) 得到 \(1\)

    之后可以得到 \(2^k\) 了。

    如何分解一个数

    从高位开始分解,我们记当前位置为 \(t\)\(t + 1\) 以上位置的数和为 \(ret\),注意到 \(\sum_{i = 0}^{t - 1} 2^i < 2^t\),于是可以令 \(cur = ret + \sum_{i = 0}^{t - 1} 2^i\),如果 \(cur < A\),那么 \(A\) 这一位就是 \(1\),否则就是 \(0\)

    接着要更新 \(ret\),如果有 if 语句,这个是非常好做的,但是没有,于是我们只能在这个返回的大小上面做文章,我们直接让这个值 \(\times 2^t\) 即可。


    之后的实现是平凡的,在此略去。 ↩︎

posted @ 2022-08-04 11:56  Werner_Yin  阅读(164)  评论(0编辑  收藏  举报