zoukankan      html  css  js  c++  java
  • ATCoder 做题记录

    AGC 备忘录

    Notes

    • Beginner:过于简单因此没进备忘录的题
    • Easy:能在几分钟内秒掉或者一眼看出了做法的题
    • Medium:自己想出了正解或大部分思路的题,或一些正解不难但很有迷惑性的题。
    • Hard:自己只想到了个大方向或者束手无策的题
    • Insane:完全想不到,几乎理解不能的题
    • 加号:该难度中相对难的题。
    • 减号:该难度中相对简单的题。
    • 前一个难度的加号约等于后面一个难度的减号,用于区分个人差。

    AGC001

    D (Easy)

    一段长度为 (i) 的回文事实上就是限制了 ((1,i),(2,i-1),(3,i-2)) 这样的字符必须相同。

    注意到一段长度为 (L) 的区间会给这个序列加 (lfloorfrac{L}{2} floor) 个限制,而我们至少需要 (n-1) 个限制,所以显然 (n) 是奇数就一次都不能浪费,也就是 (a,b) 都只能有一个长度为奇数的段了。

    然后如果 (n) 是偶数我们就可以浪费一次,所以可以分为 (a)(0)(2) 个长度为奇数的。

    一个非常强的构造策略是我先输出一个 (1),然后全部复读,不难发现这样对于偶数就是合法的,但是错了一位,把错的那位放到开头末尾和奇数的段即可。

    E (Easy+)

    组合意义。

    ((-x,-y)) 走到 ((z,w)) 的合法路径数就是 (inom{x+y+z+w}{x+z})

    因此我们直接把走到起点的路径数设为 (1) 然后递推一遍,在所有终点处统计贡献。

    这样求出的是 (sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}f(i,j)),不要忘记稍微处理一下。

    F (Hard)

    考虑排列中值为 (i) 的位置为 (a_i)

    那么我们能交换 (a_i)(a_{i+1}) 当且仅当 (|a_i-a_{i+1}|geq k)

    于是我们发现,如果 (|a_i-a_j|<k),无论怎么样它们都不能被交换,也就是说它们的关系已经被固定。

    大胆猜测固定所有 (|a_i-a_j|<k) 的对同样是构造排列的充分条件,同样可以证明。

    因此我们转化回去,就变成了给一个序列,差 (<k) 的下标的相对关系已经固定,求可能的最小排列。

    这个东西就可以建 DAG 了(然后这里粉兔说明了一些题解的问题)。

    于是一个点的入度就是 (a_{i-k}sim a_{i+k}) 里面比它大的数的数量,直接暴力上数据结构即可。

    AGC002

    D (Easy)

    整体二分基础练习题。

    E (Medium)

    考虑把博弈的网格画出来,然后找到一个厉害的结论:一个点和它左下的胜负态相同。

    然后直接搞一下就做完了。

    F (Hard)

    (f_{i,j}) 为放 (i) 个白球后放完 (j) 种其它颜色球的方案数。

    然后每次可以在最前面放一个白球或者在后面的位置随便放 ((k-1)) 个同一种颜色的新球。

    注意 (igeq j)

    AGC003

    D (Medium)

    非正解。

    首先有个 (O(nv^frac{1}{3}+nfrac{sqrt v}{log v})) 的做法,过不去。

    然后换成 (O(nv^frac{1}{3}+nv^frac{1}{4})),就过去了。

    你不想写 pollard-rho,于是你发现两个数都大于 (sqrt v) 的匹配其实巨少,直接跑到 (5) 秒把剩下的都当没匹配直接加进答案里就过了。

    E (Medium)

    首先离线一下操作,显然如果两个操作有 (a_igeq a_{i+1})(a_i) 就没用了,于是我们可以把 (a_i) 转成递增的。

    (f(n)) 为前 (n) 个元素的贡献,显然我们可以找到 (<n) 且最大的 (a_i),记这个东西的值为 (x),就可以将 (f(n)) 拆成若干个 (f(x)) 和一个 (f(n ext{ mod }x)) 了。

    时间复杂度 (O(nlog n)),因为 ( ext{mod}) 函数每次至少减半。

    F (Hard)

    因为题目是一个递归的形式,我们尝试现在 (2) 层递归中找规律。

    我们发现在两个复制的交界处一定是上下交界或者左右交界。

    于是考虑交界能否有交:显然在原图上有交的话,在每一层都会有交,反之亦然。

    那么枚举一些情况:

    • 上下左右都没有交,显然每次连通块都一分为黑格数量个,答案为 (cnt^{k-1}),其中 (cnt) 为黑格数量。
    • 上下左右都有交,显然每次递归完后都仍然联通,答案为 (1)
    • 只有上下有交或只有左右有交,下面描述如何处理。

    首先如果只有上下有交我们直接旋转 (90) 度,这样就只有左右有交了。

    然后我们发现,在 (2) 层递归的图中,只要原图里有两个相邻的黑格,答案就会减 (1),初始答案为 (cnt^2)

    类似地,我们只需要求出在 (k) 层递归图中有多少相邻的黑格就可以算了。

    这是一个简单的问题,直接矩阵快速幂就做完了。

    AGC004

    D (Easy)

    注意到 (1) 必须是自环。

    然后 (1) 肯定在基环树上。

    于是把 (1) 拆掉之后就是一棵树了,随便做。

    E (Hard)

    首先让所有机器人移动的细节非常多,我们考虑只让出口移动。

    假设出口的移动范围为一个矩形 ({i,j,k,l})

    这样的话出口对应的矩形和原矩形就会有一个交,这个交外面的格子要么已经被收集了要么一定白给了,所以这个东西可以作为一个 dp 状态。

    我们设 (f_{i,j,k,l}) 为这个移动范围下已经被收集或白给的格子中,最多被收集的数量,每次转移即可。

    F (Hard)

    考虑树的情况。

    如果我们把奇数层的节点染黑,一次移动就等价于把两个不同色相邻节点翻转,也就是移动一步黑色节点。

    于是问题变成了奇数层有一些节点,每次可以移动一个,问多少次才能使所有白色节点变黑。

    考虑每条边的贡献即可。

    然后套一个环直接考虑断环为链。

    如果是偶环我们依旧枚举某条边贡献,可以发现是一个经典模型。

    最后说一下卡了我很久的奇环:这条边的操作一定让黑点 (+2) 或者 (-2),显然黑白点相等后就不会再操作,所以直接加权值即可。

    AGC005

    D (Hard-)

    考虑钦定 (i) 个点不合法,但是仍然满足是一个排列的方案数。

    我们发现给同行同列不合法的点连边之后一定是若干条链,求链上独立集。

    于是就非常好做了。

    E (Hard)

    记先手在 A 树上走,后手在 B 树上走。

    首先发现一个结论:如果存在两个 A 树上相邻的点在 B 树上的距离 (geq 3),并且先手能走到那个节点,那么答案就是 (-1)

    假设不存在上面那类边,也就是说 A 树的边在 B 树上的边的长度 (leq 2),这样我们发现是必然走不出这个子树的,直接 dfs 所有能走到的点,对答案取最大值即可。

    F (Medium+)

    考虑计算每个点算的次数,其实就是 (inom{n}{k}-sumlimits_{iin e_x}inom{sz_i}{k})

    于是我们只需要对 (k=1,2,cdots,n) 求出 (sumlimits_{i=1}^nc_iinom{i}{k}) 即可,显然 (c_i) 直接一遍 dfs 就可以求了。

    于是推推式子:

    [egin{align} f_i&=sum_{j=i}c_jinom{j}{i}\ f_i&=sum_{j=i}c_jfrac{j!}{i!(j-i)!}\ i!f_i&=sum_{j=i}c_jj!frac{1}{(j-i)!}\ A_{i}&=sum B_{j} imes C_{j-i}\ A'_{n-i}&=sum B'_{n-j} imes C_{j-i}\ end{align} ]

    就做完了。

    AGC006

    C (Easy)

    不难发现只需要维护坐标期望即可,真实坐标没啥用。

    然后坐标期望是非常好算的,我们可以获得一个 (O(nm)) 做法。

    然后发现 (n) 次操作后相当于期望值乘上了一个排列。

    于是直接倍增即可,时间复杂度 (O(nlog m))

    D (Medium)

    首先二分。

    二分完之后,我们发现如果有两个相邻数都是 (1)(0) 的,它们一定能一起上升到上一行。

    于是求出包含中间的一段最小稳定段分类讨论即可。

    E (Medium)

    首先可以把每一列抽象成它最后的位置和它当前的正反。

    一次操作可以看成交换 (a_x)(a_{x+2}),并将 (a_x,a_{x+1},a_{x+2}) 都反过来。

    于是我们求出奇偶数位置的逆序对数和初始状态中被反过来的对数。

    确认奇偶性即可。

    F (Medium+)

    这个题看起来巨大像图论题,我们考虑转化成图论,也就是对于任意黑格 ((x,y)),从 (x)(y) 连有向边。

    如果 ((x,y)) 变黑了,那么一定存在 ((y,a),(a,x)) 使得它们都是黑的,于是我们可以把一条正向边转化成两条反向边,又可以把一条反向边转化成两条正向边。

    这样可以怎么建模呢?我们考虑把正向边看作 (+1),反向边看作 (-1),这样模 (3) 意义下就对了。

    现在我们把边拆成 (+1)(-1) 的两条,要求任意两个点是否可以走 (sum)(3) 等于 (1) 的边到达。

    注意如果边都是一个集合连另一个集合是不可能生成新的边的,要判掉。

    AGC007

    C (Hard-)

    你需要观察到一点:在推掉其中一个球之后,剩下球和盒子的距离的期望仍然是等差数列!

    于是就做完了。

    这也太神仙了吧?

    D (Easy+)

    最后方案一定是割成若干段,每次先走到一段的最右边,再走回最左边,再走到最右边。

    然后直接优化一下决策点记录一下历史状态就好了。

    注意一些很小的细节。

    E (Medium+)

    首先我们发现是求一个 dfs 序。

    如果确定好 dfs 序之后怎么做呢?

    我们可以用一个 dp 统计答案:(f_i=max(f_l,f_r,g_{l,1}+g_{r,0}),g_i=(g_{l,0}+w_l,g_{r,1}+w_r))

    时间复杂度非常劣,但是我们发现这个东西完全可以二分。

    二分之后我们相当于维护了一个合法的集合,去掉被二维偏序的点之后还剩一些较小值递增较大值递减的状态。

    这个时候我们发现,合并的时候就可以直接启发式了!我们对于 size 较小的去搞一下,然后证明一下总状态数并不会太多就行。

    F (Hard-)

    考虑答案一定是选一些字符,这些字符不断向右延伸,出现冲突就新开一列。

    我们可以发现它们尽量向右挤是最优的。

    于是直接把匹配的位置算出来求每一列会有几次冲突即可。

    AGC008

    D (Easy)

    按照 ((a_i,i)) 排序,然后每次将最前面有空的数用来垫着。

    全部弄完之后再对于剩下的元素做一遍,每次也将最前面有空的数拿来垫着。

    最后检查一遍是否合法即可。

    E (Medium+)

    首先我们把 (i o a_i) 表示成 (i)(a_i) 连边,形成内向基环森林。

    于是构造的排列就必须保证 (i)(a_i) 的距离 (leq 2) 了。

    稍微手玩一下可以得到结论:

    • 一个不是自环的连通块一定最后还在一个环中。

    • 一棵内向基环树可以分两种情况:只有环,和有环上的点。

    • 两个长度相等的环可以结合在一起。

    • 一个长度为奇数的环可以自己反一下。

    • 一棵内向基环树如果不是一个环,不能和其它树合并。

    于是问题变成了两个子问题:

    • (n) 个点,两个点可以套在一起,有 (k) 种方法。
    • (n) 条线段,每条线段可以选择覆盖 ([i,r]) 或者 ([(i+1)\%n,(r+1)\%n]),问方法数。

    好像都很水,于是就做完了。

    F (Hard)

    首先我们知道答案肯定不是每个点最大扩展次数的和,因为会算重

    我们考虑所有算重的方案,显然会存在一个 (d) 最小的(也就是说 (d) 相同,(x) 不同所构成的点集也一定不同),我们就考虑只对于这样的 ((x,d)) 计数。

    然后我们考虑判定一组 ((x,d)) 是否合法:对于所有和 (x) 相邻的节点 (y),如果 ((x,d))((y,d-1)) 相等,那么 ((x,d)) 不合法,反之合法。

    也就是说,合法当且仅当去掉任意一棵子树后,都存在一棵子树的深度 (geq d),即第二深的子树深度 (geq d)

    特别地,覆盖整棵树可能不满足上面的规律,所以我们不统计整棵树对应的点集,在最后 (+1) 即可。

    于是你把其中的一个 subtask 做完了,接下来考虑只能选其中部分点的情况。

    那么其实也就是每个点多了一个下界,重点在于怎么计算这个下界。考虑用别的点替代一定是在某一棵子树里选一个点,然后把这个子树全选完,因此考虑所有有可以选的点的子树,取最小的深度即可得到下界。

    AGC009

    C (Easy)

    考虑平方 dp:(a_{i}) 属于集合 (A/B),上一个属于另一个集合的是 (a_j)

    于是 (f_{i+1,i,A}) 等于一段区间的 (f_{i,j,B}) 的和,暴力计算这段区间即可。

    注意有些时候因为 (a_{i+1}-a_i<A) 一个前缀都会变成 (0),需要处理一下。

    D (Hard)

    就是点分治,问分治最少层数。

    我们发现答案显然 (leq log n),考虑 (O(nlog n)) 的 dp。

    考虑点分树的一个描述:点分树上深度相同的点的路径肯定经过一个深度更小的点。

    这个描述非常友好:我们发现如果我们将一些点的深度 (+1),这一点仍然满足。

    于是我们依次枚举并判断即可。

    E (Medium)

    首先我们考虑每个数对答案的贡献,就是 (a_i imesfrac{1}{k}^{t_i}),其中 (t_i) 是这个数被操作的次数。

    我们发现一个事实:我们可以构造出任意一组 (sum frac{1}{k}^{t_i}=1) 对应的操作序列!

    于是问题变为了找若干个符合要求的小数,直接 dp 即可。

    感觉这题反而没有 D 难,为啥洛谷上是黑的啊。

    AGC010

    D (Easy)

    对于 (nleq 2) 特判。

    然后你发现如果在不能改变数的奇偶性的情况下答案和所有数减 (1) 的和的奇偶性有关。

    也就是说一个人如果发现他要输了,必须想个办法使得 (gcd) 是偶数,即所有数都是偶数。

    这显然等价于场上只剩下一个 (>1) 的奇数且没有 (1),此时他的操作也唯一,因此世界线收束。

    迭代不会超过 (log n) 轮,因此时间复杂度 (O(nlog nlog a))

    E (Hard)

    显然如果两个数不互质那么它们的相对位置就固定了。

    首先我们考虑先手确定了这张图。

    那么后手只要不断取出 (deg=0) 的点中编号最大的点即可。

    于是先手反过来使得每个连通块这么做的字典序最小就是最优解。

    时间复杂度 (O(n^2log a))

    F (Medium+)

    现在假设先手从 (1) 挪到 (x)。如果后手在 (x) 这棵子树必败,那么它走回去之后先手可以再挪回来,因此后手必败。

    唯一的问题是如果 (a_1leq a_x),会出现 (1) 先变不合法的情况,此时不能走这个分支,而其它情况都是可以的。

    于是我们成功地把判断一个点是否必败分解到它的子树是否必败,对于每个节点 dfs 计算一次即可。

    时间复杂度 (O(n^2))

    AGC011

    D (Easy+)

    手玩一下发现如果第一个墙激活了就会直接被弹回来,不然就可以走到第二个墙的右边,此时第二个墙又被激活,不断重复后就走到了另一侧。

    然后对于走到另一侧的情况,对于每个墙,如果下一个墙一开始是激活的那么这个墙一定变成非激活,如果下一个墙一开始是非激活的那么这个墙一定被激活,而最后一个墙一定被激活。

    也就是说我们要执行这样的操作:循环右移一位并取反所有数,将开头的 (1) 变成 (0)

    不难发现这个操作一定以 (2n) 为循环节,直接暴力 (O(n)) 做就行了。

    注意 (k<2n) 的步不一定在循环里,需要暴力做。

    E (Medium)

    可以发现其实一个上升数就是九个形如 (111cdots1) 的数的和。

    然而 (111cdots 1) 并没有什么优美的形式,我们考虑整体乘 (9)

    于是一个上升数就是九个形如 (10^x-1) 的数的和。

    也就是说, 我们要求出 (x) 至少要表示成多少个形如 (10^x-1) 的数的和。

    注意到这个答案一定不会很大(最多为 (9log x))我们可以直接从小到大枚举并判断。

    于是我们只要支持高精度位数和和加 (1) 即可,时间复杂度 (O(nlog x))

    F (Hard+)

    照抄 command_block 了,因为实在太过神仙。

    显然因为 (k) 个时刻会发一辆新车,所以所有车通过轨道的时间都可以对 (k) 取模。

    (p_i) 为向右的车在 (i) 停靠的时间,(q_i) 为向左的车在 (i) 停靠的时间。

    我们可以列出从左向右的车通过第 (x) 个区间的时间为 (sumlimits_{i=1}^{x-1}a_i+sumlimits_{i=0}^{x-1}p_isimsumlimits_{i=1}^{x}a_i+sumlimits_{i=0}^{x-1}p_i),而从右向左的车通过第 (x) 个区间的时间为 (-sumlimits_{i=1}^{x}a_i-sumlimits_{i=0}^{x-1}q_isim-sumlimits_{i=1}^{x-1}a_i-sumlimits_{i=0}^{x-1}q_i)

    如果我们设计的方案合法的话,这个区间是不会有交集的,也就是说这两个集合的交集应该是空的。

    稍微整理一下可以得到一个优美的式子:(sumlimits_{i=0}^{x-1}p_i+q_i otin(-2sumlimits_{i=1}^{x-1}a_i,-2sumlimits_{i=1}^{x}a_i))

    做到这个形式之后就非常简单了,每次把这段区间的数放到右边就可以了,可以直接线段树维护 dp。

    感觉这题非常困难……准备给后面更困难的题开新等级了。

    AGC012

    C (Easy)

    我们发现如果我们能钦定后一半,那么数量可以转化为前一半符合某种条件的子序列数。

    注意到字符集很大,我们尝试构造一个排列。

    我们先输出这个排列,再输出一个 (1sim n) 的排列,那么答案就转化为了长度为 (n) 的上升子序列数量。

    直接倍增构造答案即可。

    D (Medium)

    考虑这个交换和这个数在哪个位置根本没有关系。

    于是如果 (x,y) 可以交换,(y,z) 可以交换,那么 (x,y) 也可以交换,因此我们就可以划分出若干个可以交换的集合,对于每个集合求阶乘即可。

    对于每种颜色,同色交换事实上就等价于有一部分数能和 (w) 最小的数交换,异色交换就等价于其中一种颜色 (w) 最小的能和另一种颜色的一些球交换。

    于是剩下的部分是非常平凡的,求出每种颜色内部的集合和颜色之间的连边即可。

    E (Medium)

    如果你做不出来,一个提示:(V) 的值域只有 (2 imes 10^5)

    不难发现 (log V) 次跳跃之后 (V) 一定变为 (0),每次跳跃之后能走的都是一个区间。

    然后我们就把 (frac{1}{2}V,frac{1}{4}V,cdots,1) 分给左边的前缀和右边的后缀,如果存在一种分法就是 possible。

    显然我们可以算出使用集合 (s) 时最长能覆盖多长的前缀/后缀,唯一的问题是,如果我们对于每个点暴力 check,时间复杂度是 (O(nV)) 的。

    事实上对于每个长度为 (V) 的极长区间的答案都是一样的,而如果极长区间的数量超过了集合中数的数量一定无解,因此时间复杂度降低到 (O(Vlog^2V)),可以通过。

    F (Hard+)

    首先我们知道 (a_ileq b_ileq a_{N-i})

    (b_i=x),然后我们知道每次如果我们加两个小于 (x) 的数 (x) 就会变成 (x) 的前驱,加两个大于 (x) 的数 (x) 就会变成 (x) 的后继。

    注意到一个数和前后缀之间一定不会相隔其它的数,所以对于任意 (i>j),肯定不存在 (b_i<b_j<b_{i+1})

    在这基础上,我们可以证明以上两个条件已经充分,从后往前构造序列即可。

    于是在这个结论下,我们可以设计一个从后往前的 dp:(f_{i,j,k}) 代表要选 (i) 位,前面还有 (j) 个数可选,后面还有 (k) 个数可选的方案数。

    转移是平凡的,时间复杂度 (O(n^4))

    AGC013

    D (Easy+)

    我们可以把放进去一个红球,拿出来一个蓝球改成放进去一个指定球。

    于是我们考虑转化成现在只有 (n-1) 个球,做 (m) 个放球,拿球的循环(如果先拿球可能存在一些特殊的 case),最后答案乘以 (2)

    这样就等价于你可以做 (m)(pm1,0) 的操作之后求极差 (leq k) 的操作序列数量。

    这个题就比较平凡,先枚举极小值,然后因为 (n,mleq 3000) 的特性直接暴力 dp 转移即可。

    E (Easy+)

    首先这个 (prod a_i^2) 看起来非常阴间,我们直接大力组合意义拆成在区间里选一个点打一种标记,再选一个点打另一种标记。然后这一切就都好起来了!

    (f_{i,0/1,0/1}) 表示放完前 (i) 个,是否打第一种标记,是否打第二种标记,非常好写出转移。

    然后如果某个位置被禁了,就代表不能在这个位置新开一段,因为只有 (10^5) 个位置,我们直接暴力转移。

    时间复杂度 (O(mlog n)),常数应该比较大。

    F (Hard+)

    首先我们都知道对于两个已经确定的序列,只需要检验对于任意一个值 (v)(a) 序列中 (leq v) 的数的数量都多于 (b) 序列中 (leq v) 的数的数量。

    于是我们直接转化,就变成了有一个序列和若干区间,每次给一个后缀临时 (+1),问至少要选择多少区间 (+1) 才能使得每个数 (geq 0)

    我们考虑有没有不依赖于后缀的决策:显然对于一个 (leq -2)(v) ,它必须被覆盖到至少 (-1)

    然后最后相当于我们只需要覆盖一段前缀的 (-1),我们可以对于每个前缀分别求出答案。

    特别注意的是,第一遍我们应该从后往前依次处理,不然如果 (4) 需要一个区间,我们选了 ([2,6]),但是如果覆盖了 (2) 开始的后缀,最优的方案应该是选 ([1,5]),这个贪心就错误了。

    AGC014

    D (Easy)

    如果一个点有两个叶子显然木大。

    如果一个点有一个叶子显然可以把这个点先选强迫后手选那个叶子,这样就可能产生更多叶子。

    直接选择一个非叶子节点 dfs 模拟即可。

    E (Easy)

    注意最后一次连边,一定是直接一条蓝边换一条红边。

    而这次连边之前,显然这条边一定要被保留,所以直接将这两个点合并即可。

    代码有一些小细节。

    F (Hard)

    对于 (i=1),显然这个数不会影响别的数是不是前缀最大值。

    于是其实我们先求出 (i=2sim n) 的答案,然后再看看这么多次之后是否 (1) 也归位了。

    显然在 (i=2sim n) 的倒数第二步完成时,此时 (2sim n) 的第一个数显然不是 (2)

    我们考虑将第一个数 (x)(1,2) 的位置关系求出,然后证明一个非常厉害的事情:这三个数相对的循环顺序不会改变。

    具体证明基于一个结论: (x) 当且仅当在第一个位置时是前缀最大值,其它情况都不是前缀最大值。

    于是在最后一步完成时,如果我们在所有操作前的相对顺序是 (1,2,f),那么 (1) 就自动归位了。不然第一位上的数还是 (2),就需要再合并一次。

    直接模拟这个过程扫一遍就行了。

    AGC015

    D (Easy)

    考虑不断求包含最高位的数有多少能被表示。

    假设现在同时存在有最高位的数和没最高位的数。

    不含最高位的数能构造的数显然在 ([l, 2^x))

    包含最高位的数构造的数显然在 ([2^x,2^{x} ext{ or }(2^{x}+1) ext{ or }cdots ext{ or }r))

    将它们的并集加入答案,并将最高位的数都丢了,分解成子任务。

    如果所有数的最高位相同,显然所有能构造的数都包含最高位,减去最高位后分解成子任务即可。

    时间复杂度 ( ext{polylog}(r))

    E (Medium-)

    注意所有点最后一定按照 (v) 排序。

    对于第 (i) 个点,如果有第 (j) 个点最开始在 (i) 后面,最后在 (i) 前面,那么 ([i,j]) 的所有点显然都在 (i) 被初始染色的时候染上色。

    于是我们可以算出第 (i) 个点的染色区间 ([l,r]),显然 ([l,r]) 有单调性,随便 dp 一下就可以了。

    F (Hard)

    我们要构造答案越大越好,注意到如果 (x<y)((x,y)) 会变成 ((ymod x,x)),我们直接反向构造,从 ((0,1)) 开始反推。因为我们要让用的数尽可能小,我们显然会从 ((y,x)) 推回 ((x+y,x))

    最后会发现其实最小的最深答案就形如 ((Fib_i,Fib_{i+1})),因此答案也只有 (log n) 级别。

    考虑哪些数对可能可以这样反向构造回去。显然构造的方法就是不断推回 ((kx+y,x))

    不难发现 (k) 在除了最后一步的位置只能取 (1)(2),不然可以证明如果这样存在解则存在一个答案更大的解。同样不难发现的是 (2) 只能选一次,证明的方法是类似的。

    因此我们还证明了除去最后一层,反向构造在最后一步之前只能构造出层数个解。

    于是我们直接对于所有解求出最后一步能得到几个合法对即可。

    注意在只有一层的时候特判。

    AGC016

    D (Not solved)

    我们记所有数的异或和为 (S),显然每次的操作就是交换 (a_i)(S)

    我们考虑对于所有 (a_i eq b_i)((a_i,b_i)) 连边,对于每条边答案 (+1),每个连通块答案 (+1)

    最后注意如果存在 (b_x=igopluslimits_{i=1}^n a_i),可以省去一次。

    E (Medium-)

    每只鸡的情况要么是一定死,要么是可能活下来。

    如果一只鸡可能活下来,那么一定存在一个集合 (S),只有集合 (S) 中的鸡全在某次选择中被献祭才可能让最后的某只鸡活下来。

    我们可以依次模拟所有操作,如果某次操作为两只都有可能存活的鸡 ((x,y)),那么 (y) 的集合就要或上 (x) 的集合,并且 (x) 的集合也要并上 (y) 的集合。

    特别地,如果两个集合交集为空,显然这两只鸡都必死,因为一只鸡没有办法献祭两次。

    最后枚举集合判断交集是否为空即可,时间复杂度 (O(n^3+nm))

    F (Medium)

    不难扯到 SG 函数上做。

    我们考虑直接钦定每个点的 SG 函数,然后要满足以下要求:

    • (sg_i=A) 的点要对于每个 (B<A) 向至少一条 (sg_j=B) 的点连边。
    • (sg_i=A) 的点之间不能连边。

    那么我们考虑钦定一个点集是合法的,每次加一个新的点集,加入的点集的 SG 函数都是原点集的 SG 函数最大值 (+1)

    再看看要满足什么要求:这些点之间的边全部不取,对于每个集合外的点和新选的点之间的连边要至少选一条边。

    可以做到 (O(n3^n))

    AGC017

    D (Easy)

    经典 SG 函数练习题。

    我们尝试表示一棵子树的 SG 函数。

    不难发现,如果加入一棵子树,因为子树可以变成任意操作后状态或者直接消失,所以相当于 SG 函数异或上 (f_y+1)

    检查 (f_1) 是否为 (0) 即可。

    E (Medium)

    讲个笑话,我一直以为可以翻转。

    记一个点某侧的权值,接地为 (-a_i)(b_i),没接地为 (c_i)(-d_i), 显然两个点能连当且仅当权值相等。

    于是大力边转点,我们就要从一个正数点开始,走若干个有向边到负数点。

    注意到可以不连成一段,所以可能会走多次。我们建一个超级起点和超级终点,检查是否在增加若干条这两个点之间的边后存在一条欧拉回路即可。

    具体来说就是每个正数点出度都不比入度少,负数点同理,并且不能有一个连通块内部消化完了。

    F (Medium+)

    显然的思路:放完 (x) 根线,状态为 (S) 的方案数,时间复杂度高达 (O(4^{n} ext{poly}(nm)))

    问题在于我们一次枚举了过多的状态,我们尝试分解每层的状态。

    考虑放完 (x) 根线,第 (x+1) 根线覆盖部分方案为 (A),未覆盖部分方案为 (B),两个状态之间距离为 (d)

    时间复杂度为 (O(2^nn^2m)),空间复杂度 (O(2^nn)),无法通过。

    我们发现覆盖的特殊要求就是 (A) 的前缀 ( ext{popcount}) 要大于等于 (B) 的前缀 ( ext{popcount})

    所以可以不记录到某一位的距离,记录第 (i) 条线走完前 (j) 步,已经覆盖的位为 (A),剩余要覆盖的位为 (B) 的方案数即可。

    AGC018

    D (Easy+)

    首先对于哈密顿回路的问题是经典的,就是每条边的边权乘 (min(sz_x,sz_y))

    对于哈密顿路,显然我们只需要扣掉一条边。

    我们考虑哈密顿回路的构造方式,核心就是要每次进入以重心为根的不同子树。

    因此我们扣掉一个点只需要扣掉最后回重心的那个点即可,答案只需减去重心的出边中距离最短的那条。

    特别注意的是如果有两个重心,那么只有它们之间的边是两个重心的公共出边,特判即可。

    E (Not solved)

    F (Not solved)

    AGC019

    D (Not solved)

    E (Not solved)

    F (Hard-)

    显然如果还剩 Yes 多我们就猜 Yes,不然猜 No。

    于是我们放到二维平面上,每个决策可以表示成一条边,数所有路径经过的决策边数量之和即可。

    唯一的问题是决策边的数量并不好数,是这个形状的:

    我们考虑把每条边超出斜线的部分强行折回去,然后加上 (0.5) 的贡献(因为一定会走一条超出斜线的竖边)。

    计算斜线上的每个点被经过的路径条数即可。特别注意因为事实上我们没有折回去,所以计算的其实就是走到左下的路径数量乘以走到右上的路径数量。

    AGC020

    D (Not solved)

    E (Not solved)

    F (Not solved)

    AGC025

    D (Easy+)

    对于所有距离为 (D_1) 的点连边,可以证明这是一张二分图。

    取出点较多的一侧,对于所有距离为 (D_2) 的点连边,仍然可以证明这是一张二分图。

    因此最终至少可以选出 (lceilfrac{lceilfrac{4n^2}{2} ceil}{2} ceilgeq n) 个点。

    E (Hard)

    抛出一个结论:所有被经过至少两次的边都能提供 (2) 的贡献。

    考虑每次选一个叶子。

    如果这个叶子没有连向父亲的路径,那么我们什么都不用考虑,直接删点即可。

    如果只有一条连向父亲的路径,我们就之后再考虑,将这条路径的起点改为它的父亲。

    如果有 (geq 2) 条连向父亲的路径,我们选一条定一个方向,再选一条定反方向,剩下的随意。

    设这两条路径的终点分别为 (a,b),它们从当前结点 (x) 分开的位置为 (t),显然 (x o t) 的路径肯定被覆盖两次,而 (t o a)(t o b) 因为方向相反可以变成 (a o b) 的路径。显然因为这个节点是叶子,(x) 肯定不等于 (t),所以我们成功地将问题缩小到了相同条件的更小规模,反复操作即可。

    由于数据范围很小某些地方可以复杂度换码量,然而细节还是很多。

    F (Hard-)

    每次操作可以看成是从高到低,对于每个都为 (1) 的位产生一次进位,并处理随之带来的进位。

    我们发现一件神奇的事情:我们可以对于从高到低的位,直接产生至多 (k) 次进位,与上述操作等价。

    证明可以使用归纳法,在我们增加一次的时候,如果某一位上都是 (1), 那么这一位进位之后位置上的数一定是 (0)。而即使它下面的所有位都全为 (1),这一位也无法继续进位。

    此时我们得到了一个 (O(nk)) 的暴力,考虑继续优化。

    我们发现只有在 ((01,01)) 的情况下对低位进位不会减小 (0) 的个数,于是我们将连续的 ((0,0)) 段压在一起存之后暴力模拟,时间复杂度即为 (O(n))

    有趣的事实:zhoukangyang 没有使用这个性质也切掉了此题,大家可以膜拜他。

    AGC055

    A (Easy+)

    我觉得比 B 难。

    将字符串分成三段,每次枚举一个 ABC 的排列 (s),尝试在第 (i) 段中找出尽可能多的 (s_i),取最小之后将这些字符取出即可。

    可以通过一些方式证明最后一定能取完。

    B (Easy)

    首先我们发现无论怎么操作每种字符的数量都是不变的。

    注意到一个性质:如果有一个 ABC,它可以和任意一个字符交换。

    于是我们直接对于 (s,t) 寻找 ABC 并移到最前面即可。

    当没有东西可以移动时能否转换等价于剩下的两个串是否完全相同

    C (Medium-)

    一个显然的性质:所有数的答案要么是 (L-1),要么是 (L),其中 (L) 为序列的 LIS 长度。

    于是一个很自然的想法是枚举哪些位置是 (L-1)

    枚举完哪些位置是 (L-1) 之后,我们发现我们要求的就是 (L) 的最大值和最小值。

    最小值是显然的,也就是 (L-1) 的位置数量,构造为剩下的数全选 (+infty),注意要和 (3)(max)

    最大值应该是在每个空隙中尽可能塞若干对数。

    例如,我们选择 ({1,3,6,8}),那么我们可以让 (a_3<a_4=a_5<a_6),那么这样 LIS 长度就增加了 (1),注意 (0)(n+1) 都必须选上。

    不难发现能塞的对数和选的数的数量只和长度为奇数的空隙有关,枚举选的数的数量和长度为奇数的空隙计算即可。

    注意选所有数和不选数是两种情况。

    D (Hard)

    神仙结论题。

    (A_x) 为序列所有前缀 (A)(B) 多的数量的最大值,(B_x)(C_x) 的定义类似。

    抛出一个神仙结论:序列可以被分解当且仅当 (A_x+B_x+C_xleq n)(A,B,C) 各有 (n) 个。

    必要性显然,充分性也可以通过一些技巧证明。

    于是直接大力 dp 就可以了。

    E (Not solved)

    F (Not solved)

  • 相关阅读:
    Python Socket 网络编程之粘包现象
    Socket 通信流程和 Python 网络编程基础
    WAF 技术原理
    Python 反射机制(自省)
    Python中创建对象的内部流程、metaclass和type类
    理解Python可迭代对象、迭代器、生成器
    Python 面向对象编程 总结
    python类的继承
    【macOS】关闭mac的Microsoft AutoUpdate
    tampermonkey修改页面音频播放地址
  • 原文地址:https://www.cnblogs.com/dead-X/p/15438816.html
Copyright © 2011-2022 走看看