AT
一些 AtCoder 上的题。
ABC/AGC/ARC
[ABC153F] Silver Fox vs Monster
模拟赛上被创死了。首先发现每个怪都对应着一个区间,然后发现对于最左边的区间我们只能一个个打,于是使用贪心,把与其有交的和他一块打,用差分维护血量,以此类推就做完了。code
[ABC332F] Random Update Query
对每一个元素,考虑一次操作对其影响有 \(\frac{1}{r-l+1}\) 的概率改为 \(x\),剩余的概率保留原数,所以操作对元素的影响为:
开个线段树,维护先乘后加就行了。code
[ABC281G] Farthest City
这篇第一道极具思维量的题目。
首先我们注意到 \([0,d_n]\) 这些数必须全部取到,因为最短路是由之前的 \(d\) 值确定的,且每条边长度都为 \(1\),如果其中一个数没有取到的话,那比这个数大的数都取不到。那么我们就可以考虑将图按 \(d\) 值分层,然后一层一层数数。我们知道前一层对后一层是一个子问题,于是可以 DP。
设 \(f_{i,j}\) 表示我们已经安排了 \(i\) 个点,最后一层有 \(j\) 个点共有多少种情况,这样答案就是 \(f_{n,1}\)。考虑转移。
第一步,我们要选出 \(j\) 个数,选的范围是除去终点和选好的点,对答案的贡献是 \(C_{n-(i-j)-1}^j\)。但要注意\(i=n\)的时候终点是必须选的,需要特判。
第二步,假设前面一层有 \(k\) 个点,那么这 \(j\) 个点最少要和前一层的某一个点连一条边,否则这个点就不在这一层里了。每个点的贡献是 \(\sum_{k=1}^n C_{k}^i\),由二项式定理定理知道这就是 \(2^k-1\),总共 \(j\) 个点的贡献就是 \((2^k-1)^j\)。
第三步,这 \(j\) 个点之间可以随便连,贡献是 \(2^{\frac{j(j-1)}{2}}\)。
最后我们根据加乘原理得到转移式 :
我们预处理组合数和 \(2\) 的次幂,然后敲个快速幂就可以过了,复杂度 \(O(n^3\log n)\),如果预处理 \((2^k-1)^j\) 的话可以做到 \(O(n^3)\),预处理会挂上常数,而且时间限制 4s,稳稳地过去了。难点在于想到把图根据 \(d\) 值分层。code
[ABC180F] Unbranched
发现 “恰好为 \(L\)” 的信息不好维护,考虑利用差分的思想先算出 \(\le L\) 的情况,再算出 \(< L\) 的情况,作差就行了。
又发现 “每个点度数最多为 2” 的条件,于是我们生成的图要么是链要么是环,单点算作大小为一的链。
根据经验,设 \(f_{i,j}\) 表示 \(i\) 个点,\(j\) 条边的情况。考虑转移,如果最后我们考虑到的是链,设链的长度是 \(k\),则选出这 \(k\) 个点对答案的贡献为 \(C_{n-i+k-1}^{k}\),这 \(k\) 个点的顺序对答案的贡献为 \(\frac{k!}{2}\),于是有:
同理可以得到如果最后考虑的是环对 \(f_{i,j}\) 的贡献:
然后就完了。
[ABC395F] Smooth Occlusion
考虑答案的表达式为
于是考虑求最大的 \(H\)。一种方法是二分答案,判断的时候手动砍就行了,时间复杂度 \(O(n\log n)\)。另一种方法考虑我们不管怎么砍得,反正看完之后的 \(H\) 肯定是 \(\min({D_i^{'}+U_i^{'})}\),于是考虑如何在满足 \(|U_i-U_{i-1}|\leq X\) 的条件下使得所求 \(H\) 尽量大,于是从左往右扫,把当前的值与前一个值加 \(X\) 取小然后统计就行了。code
[AGC033D] Complexity
看到题解后产生了一种欲罢不能的快感。
暴力 DP 就是设 \(f_{i,j,k,l}\) 表示 \((i,j)\) 到 \((k,l)\) 的复杂度,时间复杂度 \(O(n^5)\),显然不可过。然后发现思路死了,于是考虑注意到一些性质。发现答案最多是 \(\log n+\log m\) 的,所以考虑交换答案与状态。设 \(f_{i,j,k,l}\) 表示复杂度在 \([0,i]\),左上角坐标为 \([j,k]\),右上角坐标为 \([j,l]\) 时这个矩阵下边界的最大值。
初始状态:\(f_{0,i,j,k}=\max \{l\}\),其中 \(((i,j),(k,l))\) 所有颜色均相同。
转移:
-
考虑 \((j,k,l)\) 小于等于 \(i-1\) 时的答案可以直接贡献到当前,于是 \(f_{i,j,k,l}\leftarrow \max(f_{i,j,k,l},f_{i-1,j,k,l})\)
-
考虑横着切一刀,那么这一刀肯定是在 \(f_{i-1,j,k,l}\) 上,我们要考虑的就是这下面对答案的贡献,也就是 \(f_{i,j,k,l}\leftarrow \max(f_{i,j,k,l},f_{i-1,f_{i-1,j,k,l}+1,k,l})\)
-
考虑竖着切一刀,枚举断点 \(x\),有 \(f_{i,j,k,l}\leftarrow \max(f_{i,j,k,l},\min(f_{i,j,k,x},f_{i,j,x+1,l}))\),但是注意到 \(l\) 单调增加的时候 \(x\) 也单调递增,所以可以整个双指针
答案就是 \(\min i\),其中 \(f_{i,1,1,W}=H\)。时间复杂度 \(O(HW^2(\log H+\log W))\)。code
[ABC237F] |LIS| = 3
最开始想的是设 \(f_{i,j,k}\) 表示前 \(i\) 项中最后一个选 \(j\),\(|\text{LIS}|_{\max}=k\) 的方案数。显然这是假的,因为前 \(i\) 项中不仅仅有一个满足条件的 \(\text{LIS}\),这样做有后效性,所以考虑把后效性消除。
设 \(f_{i,x,y,z}\) 表示前 \(i\) 项,\(x,y,z\) 分别是长度为 \(1,2,3\) 的上升子序列结尾的最小值,可知 \(x<y<z\),转移时看当前的 \(j\),用 \(j\) 替换第一个大于 \(j\) 的数就可以了。code
[AGC028B] Removing Blocks
好题,自己只想出了 \(O(n!n\log n)\) 远劣于暴力的做法,看题解时感觉脑子完全被牵着走。
首先发现所求除以 \(n!\) 就是期望,似乎没用但很有用。假设我们已经固定了一个排列,第一个关键思路是建立以删除时间为基数的小根笛卡尔树,则树上节点对答案的贡献就是子树内点的权值和。转换一下,拆贡献,记 \(hdep_i\) 表示点 \(i\) 的深度,那么 \(Ans=\sum_{i=1}^ndep_i\cdot a_i\),于是问题转化为对于 \(dep_i\) 求 \(E(dep_i)\),另一个关键转化是发现等价于 \(i\) 的祖先个数。考虑一个排列以及点 \(i\),如果 \(x<i\) 并且 \(x\) 是 \(i\) 的祖先,那么 \(x,x+1,\dots,i-1\) 都应在 \(i\) 之后被删除,这样的方案数占总方案数的 \(\frac{(i-x)!}{(i-x+1)!}=\frac{1}{i-x+1}\),同理 \(x>i\) 时 \(\frac{1}{x-i+1}\) 即为所求,因此 \(E(dep_i)=\sum_{x=1}^{i-1}\frac{1}{i-x+1}+\sum_{x=i+1}^n\frac{1}{x-i+1}\),然后前缀和就可以了。code 极其短
[AGC061C] First Come First Serve
考虑一种顺序有两个对应的方案,对于一个不同的 \(i\),一定不会有其他人在 \((a_i,b_i)\) 中选择,此时 \(i\) 选 \(a_i,b_i\) 对顺序没有影响,尝试建立顺序到字典最小的方案的映射,可以认为每个顺序对应的选择方案是对于每个选了 \(b_i\) 的 \(i\),\((a_i,b_i)\) 中有被选择的元素,显然这样的方案是唯一的。考虑容斥,对于每个 \(i\),可以选择 \(a_i\) 或 \(b_i\),系数是 1;也可以选择 \(b_i\) 并钦定 \((a_i,b_i)\) 中不被选择,系数是 -1,发现对于每次这个情况,都可以确定一个 \([l,r]\) 内的选择情况,注意到哲学区间有交的时候贡献是 0,所以只需要考虑无交的情况。我们要求的答案写出来就是 \(2^n\sum_{S\subset U}[S\text{中}[l_i,r_i]\text{无交}]\frac{1}{2}\sum_{j\in S}(r_j-l_j+1)\),我们发现这个形式可以 dp,设 \(f_i\) 表示分配了前 \(i\) 个的方案数,有转移 \(2f_i\rightarrow f_{i+1},f_{l_i-1}\rightarrow f_{r_i}\),时间复杂度 \(O(n)\)。
[ARC146E] Simple Speed
发现维护了一个折线的结构,序列维很难做,考虑扫值域,设 \(f_{i,j,0/1,0/1}\) 表示考虑前 \(i\) 个值,当前有 \(j\) 对相邻的 \(i\),有 \(j\) 对相邻的 \((i,i)\),且左右端点不是/是 \(i\) 的方案数,不妨仅讨论左右端点都不插入新数字的情况,有转移
注意到 \(j\) 那一位只有 \(O(1)\) 种取值,所以时间复杂度是 \(O(n)\)。
[ARC157E] XXYX Binary Tree
自底向上递归,我们发现需要维护当前点字数内 y 的数量、叶子结点 y 的数量、当前点的颜色,发现维护这些信息就够了,但是这是可行性问题不能直接交换维度至答案。
哦这棵树是二叉树啊那一定有 C/2 个非叶子结点是 y,这样就可以把可行性问题转化为最值为题,把子树内不在叶子结点上的 y 的数量扔到答案里求最值树上背包就做完了。code
[AGC013E] Placing Squares
\(len^2\) 的形式显然要转化为组合意义。问题相当于我们要放一些隔板,有一些位置不能放隔板,对于每两个隔板中间的位置我们要放一个黑球一个白球,求方案数。容易想到 \(dp(i,0/1/2)\) 表示位置 \(i\) 前的这个隔断放了 \(0/1/2\) 个球的方案数,这玩意可以矩阵加速线性递推;对于不合法的位置改一下转移矩阵就行了。code
JOI
[AT_joi2016ho_b] スタンプラリー 2 (Collecting Stamps 2)
如果要插入 J,肯定是插在最左边最优;如果插入 I,肯定是插在最右边最优。对于 O,枚举它插在哪个数后边,算一下 J 的前缀和 O 的后缀就行了。code
[AT_joisc2014_h] JOIOJI
注意到原条件等价于 J 的数量与 O 的数量的差以及 O 的数量与 I 的数量的差均为零。我们记下 J,O,I 的前缀和 \(c_j,c_o,c_i\),记 \(x_i=c_j(i)-c_o(i),y_i=c_o(i)-c_i(i)\),于是我们只要 \((x_i,y_i)\) 在之前出现过,就说明这一段可能是答案,开个 map 记一下就行了。code
[AT_joi2014ho3] バームクーヘン (Baumkuchen)
二分答案然后用枚举断点,利用前缀和求和然后判断就行了。code
競プロ典型 90 問
洛谷不爬,题解在推特上还是日语照片,除了经典真的一无是处。
049 - Flip Digits 2(★6)
类似的 trick 在 [WC2024] 线段树 中出现过。考虑表示出一个连续 1 段 \([l,r]\) 需要什么,要么就是一些小段拼起来,要么就是两个大段把这一段整成 0 然后通过一些方法把这两个大段的并翻转,也就是说这个并是可标记的。用并查集合并 \((l_i,r_i]\),那么所有的 \(T\) 都可以被表示相当于 \(n\) 个点祖先是一样的,类似于 Kruscal 的做法按 \(c_i\) 从小到大合并就做完了。code
053 - Discrete Dowsing(★7)
第一眼是三分板子,关键在于 \(lmid\) 和 \(rmid\) 的选取。三分法函数调用次数的下界是 \(2\log_2\frac{r-l}{\epsilon}\) 的但是这个下界取不到,如果选用三等分点的话这个东西就爆炸了,因为单次迭代区间长度缩得太慢了。这里使用黄金三分,使用常数黄金分割比
每轮迭代让 \(lmid=\phi l+(1-\phi)r,rmid=(1-\phi)l+\phi r\),下一轮迭代的时候复用上一轮迭代用过的函数调用结果,每轮迭代只需要 1 次查询,这样想达到精度 \(\epsilon\) 只需要 \(1+\log_{\phi}\frac{r-l}{\epsilon}\) 次调用,渐进意义上更少。一个问题是在一般的整数三分上这样取会导致精度问题,你只需要利用斐波那契数列,令 \(k\) 为最大的 \(fib(k)\leq r-l+1\) 的数,让 \(lmid=l+fib(k-1)+1,rmid=l+fib(k)+1\) 就可以了。code
054 - Takahashi Number(★6)
研究和科学家之间建边,从高桥开始跑 bfs 即可。code
058 - Original Calculator(★4)
\((i,A(i))\) 构成了内向基环树,把环的大小求出来然后周期性解决问题。code
059 - Many Graph Queries(★7)
第一发错误提交。
我常常追忆过去,但是只用 bitset 是不够的,压得不够。我们把连续 64 个询问的可行性从 64 个 bitset 变成一个 ull,然后对着 64 个询问去建边。code
RGB Balls 2(★7)
发现可以通过题目的约束推出三种颜色分别的上下界,然后就是把其中两个卷起来和另外一个合并就行了。

浙公网安备 33010602011771号