Tag & Difficulty
Sol
难度纯粹个人评价。
3571
Tag & Difficulty
Tag: dp, observation | Difficulty: 2300Sol
一个朴素的 dp 是 $f_{i,j,k}$ 表示选择按照 ddl 排序在 i 个及其之后选物品,在第 i 个物品的 ddl 及之前还有 j 个空位能买东西,所有这样的方案中第 k 大答案。显然这是 \(O(n^2k)\) 的,但是这个过程中真正贡献到 \(f_{1,x,x}\) 的有效转移显然不会超过 \(O(nk)\)。可以用一些技巧只算出这 \(O(nk)\) 个状态。
具体地,考虑一个个求出 \(f_{1,x,1 \sim k}\)。假设现在在求 \(f_{1,x,r}\),而 \(f_{1,x}\) 从 \(f_{2,y}\) 和 \(f_{2,z}\) 转移过来(一个是不选这个物品,一个是选这个物品)。那么 \(f_{1,x,1 \sim r-1}\) 会从 \(f_{2,y}\) 的一个前缀和 \(f_{2,z}\) 的一个前缀转移过来,不妨假设从 \(f_{2,y,pre_y}\) 和 \(f_{2,z,pre_z}\)。那么 \(f_{1,x,r}\) 可以从 \(f_{2,y,pre_y+1}\) 和 \(f_{2,z,pre_z+1}\) 中选优的那个转移。如果这两个中有一个没算就递归进去算。在算完 \(f_{1,x,r}\) 之后,如果其选择从 \(y\) 转移则 \(pre_y \leftarrow pre_y+1\),否则 \(pre_z \leftarrow pre_z+1\)。先把 \(f_{i,j,1}\) 算好,对于每个 \(f_{i,j}\) 都弄个这样的 \(pre_y,pre_z\),然后可以发现在 \(f_{1,x,1\sim r-1}\) 都算完的时候算 \(f_{1,x,r}\) 只会需要额外算 \(O(n)\) 个值,这样复杂度优化到了 O(n^2+nk)。
3570
Tag & Difficulty
Tag: data structure, greedy | Difficulty: 2000Sol
对每个左端点 $l$ 用各种各样的数据结构算出能够到达的最远的右端点 $p_l$,然后连边 $l \to p_l+1$,每次询问就是问 $l$ 到 $r+1$ 要跳多少步,离线之后并查集搞搞。01.03
527
Tag & Difficulty
Tag: data structure | Difficulty: 2200Sol
左转 JOI 2015 Final T5枚举左上角和右下角,它们要在同一个左上-右下对角线上。于是直接枚举这个对角线,对于对角线上的每个点设 \(down_i\) 表示其向右和向下伸展的长度的最小值,\(up_i\) 表示其向左和向上伸展的长度的最小值,那么对于第 \(x\) 行和第 \(y(x<y)\) 行的两个点,能框出一个正方形当且仅当 \(\min(down_x,up_y) \geq y-x\),扫描线树状数组搞搞即可
524
Tag & Difficulty
Tag: game, observation | Difficulty: 1400Sol
如果有 X 而且长度不为 1,最后一个填数的人一定可以控制逆序对的奇偶。所以只需要算算没有 X 的情况下逆序对个数即可569
Tag & Difficulty
Tag: graph matching, observation | Difficulty: 1800Sol
考虑一下最优解的矩形结构是什么样的。如果矩形里面有 2 那么把这个矩形缩小成一个 2 显然更优,否则一定是等量的 1 和 3,此时一定会有一个 1 和一个 3 相邻,把矩形缩小到这两个更优。所以最后一个矩形要么套一个 2,要么套一对 13。前者直接算,后者二分图匹配。01.04
!502
Tag & Difficulty
Tag: tree, data structure, hashing, randomization | Difficulty: 2700(因为不会随机化所以可能评分虚高)Sol
显然主席树是不行的。为了保证时空效率,每个点从父亲得到的信息必定是压缩过的,同时值域还不太大,所以可以考虑整点哈希和随机化乱搞。具体地,设 \(p_i\) 表示二进制第 \(i\) 位为 1 的所有颜色出现次数和,再记一下每个点深度。这样所有颜色都是三的倍数的必要条件是每个 \(p_i\) 都是三的倍数,而恰有一个不是三的倍数的必要条件是深度不是三的倍数且每个 \(p_i\) 要么是三的倍数,要么与深度模三同余。同时我们还可以通过这样的信息还原出唯一的那个出现次数可能不是三的倍数的颜色。
这显然是可以卡的所以再整点随机:给每种颜色随机 \(k\) 个 01 权值,然后设 \(q_i\) 表示第 \(i\) 个权值是 1 的所有颜色出现次数和,然后利用额外的 \(k\) 个值对上面得到的结果进行验证。感觉错解找不出的概率是 \(\frac{1}{3^k}\)。因为只需要记录每个值模三的结果所以可以压在一个 long long 里面,我比较偷懒就压在了个 64 位 bitset 里面,可能会慢点。
01.05
2730
Tag & Difficulty
Tag: constructive, observation | Difficulty: 2100Sol
最近想的一个做法。很久以前想的那个做法我觉得比较神秘。假如说你已经知道第一张卡牌是最难记的那张,拿那张去比其他就可以直接知道答案了。所以一个想法是去找到这个 max。
考虑一张一张扫并维护每次扫到的 max。具体地,维护一个集合 \(S\),其大小可能为 2 或 3(3 是一种特殊情况),还有一个值 \(v\) 表示 \(S\) 中最好记的值是多少。保证 \(S\) 中有至多一张卡牌值不是 \(v\)。初始 \(S\) 就是前两张,\(v\) 一次询问即可。
每次扫到新的卡牌 \(x\),将其和 \(S\) 中的两个元素 \(y,z\) 进行询问,得到两个值 \(u,w\)。分情况讨论:
- 如果 \(u,w\) 相同,如果 \(u \neq v\) 那么一定是 \(x\) 最好记,而且它的答案已经出来了。把 \(x\) 丢掉考虑下一张卡牌
- 如果 \(u,w,v\) 相同且 \(S\) 中恰好有两个元素,那么现在的情况就是 \(x,y,z\) 中恰好有两个 \(u\) 但是目前信息不能判定谁是,所以把 \(x\) 丢进 \(S\)。这里体现了为什么一定要维护大小为三的集合,且满足了上面的性质。
- 如果 \(u,w,v\) 相同且 \(S\) 中恰好有三个元素,那么一定是 \(y,z\) 最好记且都是 \(v\),把它们删了然后把 \(x\) 丢进去更新 \(v\) 的值
- 如果 \(u,w\) 不相同,那么其中一个一定是 \(v\),其对应的那个元素一定是 \(v\)。同时如果 \(S\) 的大小为三,没有询问的那个数也一定是 \(v\)。把它们删掉把 \(x\) 丢进去,更新 \(v\) 的值。
最后 \(S\) 中剩下的两个元素就是最难记的。
询问只会在加入每个元素时问两次、更新 \(v\) 时问一次,而且更新之后一定更难记,所以总次数 250。
563
Tag & Difficulty
Tag: number theory | Difficulty: 2400Sol
因为每个元素在模意义下至多有一个逆元,所以设模 $m$ 下有逆元的个数为 $c(m)$,则 $f(G(m)) = 2^{\frac{c(m)}{2}}$。计算出 $c(m)$ 之后前缀和就可以了。首先有逆元的元素个数是 \(\varphi(m)\),还需要减去逆元是它本身的元素,不妨假设有一个这样的元素 \(x\)。将 \(m\) 分解质因数 \(m = \prod p_i^{c_i}\),那么在每一个模 \(p_i^{c_i}\) 的意义下有 \(x^2 \equiv 1(\bmod p_i^{c_i})\),即 \((x-1)(x+1) \equiv 0(\bmod p_i^{c_i})\)。当 \(p_i \neq 2\) 时,\(x-1\) 和 \(x+1\) 至多有一个是 \(p_i\) 的倍数,所以 \(x = \pm 1\);当 \(p_i = 2\) 时,\(c_i = 1,2\) 特判,\(c_i \geq 3\) 时注意到 \(p_i+1\) 和 \(p_i-1\) 要么都不是二的倍数,要么一个是二的倍数不是四的倍数,另一个没有限制。所以 \(x = \pm 1\) 以及 \(x = 2^{c_i-1} \pm 1\) 都是合法的。最后 CRT 求出逆元是本身的元素数量,将 2 单独考虑后也就是 \(2^{w(m)}\)。将 \(\varphi(m),w(m)\) 筛出即可。
01.06
*566
Tag & Difficulty
Tag: binary search, greedy, convex optimization, graph | Difficulty: 3200Sol
开始一直在想枚举中位数然后一直想不出做法……对于 \(n\) 是奇数的情况,把绝对值拆掉,就相当于权值大的 \(\frac{n-1}{2}\) 条边正,权值小的 \(\frac{n-1}{2}\) 条边负,要求和最大。可以发现这个条件可以宽松为恰好 \(\frac{n-1}{2}\) 条边取负,因为取负的那些元素一定是权值最小的。所以每条边都创造一个边权相反数的副本,就是要求这 \(2m\) 条边有恰好 \(\frac{n-1}{2}\) 个副本的最大生成树。这里有一个结论是最大生成树关于副本数量是凸的,但我也不会证 ????,直接用上可以得到一个 \(O(m \log w)\) 做法。
对于 \(n\) 是偶数的情况,中间有一条边权值是 0,但你可以直接把这条边丢了,也就是找一个 \(n-2\) 个点的生成森林,因为本身树是联通的所以找到一个森林之后总是能找到一条边把它们联通。同时在这个情况下最优解也一定是选 \(\frac{n-2}{2}\) 大和 \(\frac{n-2}{2}\) 小,不会存在中间连出的一条边不是中位数的情况。
!551
Tag & Difficulty
Tag: constructive, brute force, observation, game | Difficulty: 2000(guess), 2600(prove)Sol
对于第一问,可以先尝试将问题规模缩小。考虑以下策略:无论 Ball 放在哪里,Alex 都放在它旁边,然后将放置的位置所在的行列删掉,变为一个 $n-1$ 的子问题,这个子问题里没有标记。如果这个子问题有必胜策略,那么 Alex 去玩这个子问题得到一个必胜局面,加上最开始放的这个标记合并起来就是原问题的必胜局面。然后写个暴力发现 $n \leq 3$ 的时候必败,$n=4$ 的时候必胜,这样 $n \geq 4$ 的时候就都胜利。对于第二问,Alex 的放置策略只取决于 Ball 的最后一次放置,这样策略可以被表示为一个 \(n \times n\) 个点的有向图,有边 \((x,y)\) 表示 Ball 选 \(x\) 之后 Alex 选 \(y\),那么 Alex 能做的就是选这个图,Ball 做的是根据这个图选每次的放置。首先图上显然不能有自环,同时如果图上存在长度等于二的简单路 \(x\to y \to z\),Ball 可以先选 \(y\) 再选 \(x\) 然后 Alex 就会放在已经有标记的 \(y\) 上。这意味着 Alex 选择的方案必须要是一个匹配。因而所有奇数 \(n\) 都是不合法的。
此时可以更深入地想想方案需要满足的条件。为了保证每行每列都存在一个标记,Alex 的匹配方案必须要满足每行存在两个元素是匹配在一起的,每列同样。对于 \(n=4\) 来说,不能出现一行或者一列将元素全匹配完的情况,所以最终可以发现只有一种本质不同的匹配方法:第一行匹配 12,第二行匹配 23,第三行匹配 34,第四行匹配 41,剩下的空位给四列匹配。再写个暴力发现它是对的。这样的构造又为我们提供了缩小问题规模的方便:对于 \(n\) 来说,将前四行和前四列的子棋盘中匹配变成这个 \(n=4\) 的方案,下面的 \(n-4 \times n-4\) 的棋盘如果存在一个合法匹配,跟这个 \(4 \times 4\) 的棋盘拼起来可以得到合法方案。所以最后只需要 check 模 4 余 2 的最小解即可。对于 \(n=6\) 可以照猫画虎构造一个方案:第 \(i\) 行还是匹配 \(i\) 和 \((i\bmod n)+1\),然后第 \(i\) 列剩下的 \(n-2\) 个进行一个相邻元素的匹配。跑个暴力发现还是对的,然后就做完了。
01.07
摸了,写几个模板跑路
01.08
552
Tag & Difficulty
Tag: counting | Difficulty: 2300Sol
考虑枚举递增的三个位置 $a,b,c$ 算有三元环的排列数量。首先 $p_b$ 肯定不在 $[p_a,p_c]$ 里面,否则 $ac$ 不可能有边。所以枚举剩余四种偏序,不妨假设是 $p_a,p_c,p_b$ 的递增顺序。那么 $ac$ 有边必须满足中间的所有数都大于等于 $p_b$,而在这个情况下 $b$ 显然跟其他人都有边。简单枚举可以发现 $a,b,c$ 的四种偏序情况都对应一样的结果,而满足这个条件的排列数量是 $\frac{n!}{(l-2)(l-1)l}$,其中 $l = c-a+1$,这是很经典的树偏序排列数。方案数只跟长度有关所以考虑枚举长度 \(l\),选 \(ac\) 的方案数是 \(n-l+1\),选 \(b\) 的方案数是 \(l-2\),综合一下并除掉 \(n!\) 算期望,答案就是 \(4 \sum_{l=3}^n \frac{n-l+1}{(l-1)l}\),直接算是 \(O(n \log P)\) 的。
把这个式子拆一拆,\(\sum_{i=3}^n \frac{1}{l(l-1)}\) 可以裂项,可以整理得到答案等于 \(2(n+1)-4H_n\),其中 \(H_n\) 表示调和级数。分段打表即可。
!553
Tag & Difficulty
Tag: dp, brute force | Difficulty: 2600Sol
分子任务乱写人.jpg题目意思就是需要保留价值和尽可能少的数使得将它们每个减某个非负值之后异或和为 \(c\)。考虑同时保留两个数 \(a,b\),从高位向低位考虑,可以发现它们可以表示出的数集合跟 \(a\ \mathrm{or} \ b\ \mathrm{or} (2^{\mathrm{hightest\ bit\ in\ } a\ \mathrm{and} \ b} - 1)\) 能表示出的数集合是等价的,所以可以 dp 通过前两个子任务。
对于第三个子任务,可以发现选一个大于等于 \(c\) 的数可以直接完成任务,但选小于 \(c\) 的数集一定没法表示出 \(c\) 的最高位,所以从小到大排序之后每次查询大于等于 \(c\) 的数的最小权就行。
后面两个子任务是随机的,这意味着有用的集合不会特别多。设第 \(t\) 位是 \(m\) 的最高二进制位,对于给出的二元组 \((v,l)\) 集合,将它们按照第 \(t\) 位取值分为两类 \(S_0,S_1\)。\(S_0\) 中的数最多能够表示出 \(2^t - 1\),而因为约有半数的数是 \(\geq 2^{t-1}\) 的,所以选 \(\geq 2^{t-1}\) 中权值最小的两个,可以用相当小的权值 \(v_0\) 直接凑出 \(2^t - 1\),然后在 \(S_0\) 中搜索出所有权值不超过 \(v_0\) 的选择方案。毛估估期望意义下这个集合中的元素个数不超过常数。不妨假设这些选择方案构成的集合是 \(S_0'\)。
\(S_1\) 中如果有大于等于两个数可以直接凑出万能解,假设这样的最小权值是 \(v_1\)。注意 \(v_1\) 是没有好的界的,因为 \(m - 2^t\) 可以取得相当小使得 \(S_1\) 中元素比较少(虽然好像最终数据 \(m\) 都是最大范围)。然而在 \(S_1\) 中期望意义下也只有常数个元素权值小于 \(v_1\),把这样的元素跟 \(S_0'\) 做个笛卡尔积,再并上 \(S_0'\) 和 \(v_1\) 对应的方案就是所有可能的方案。
01.09
533
Tag & Difficulty
Tag: dp, brute force, observation | Difficulty: 2000Sol
因为只关心每个元素是不是对立的,这东西还是对称的,所以可以只考虑一半。从一对对立的位置把环劈开然后考虑其中一半,对于每段独立元素将它和它前面的一个对立元素看成一个整段,那么当这一半的独立段长分别是 $l_1,l_2,\cdots,l_k$ 的时候,整个环的长度就是 $2(l_1+1+l_2+1+\cdots+l_k+1)$,段长乘积是 $(\prod_{i=1}^k l_i)^2$。可以直接看成每次给答案乘上 $p^2$ 然后总段长加上 $p+1$。因为整个都是有平方的所以可以把平方跟询问的平方一起抵掉。同时一个较长的段可以劈开成若干个较短的段的和,然后可以发现在最优情况下每一个独立段的段长一定不超过 \(6\):加一个独立段长是 \(6\) 的段可以换成分别加 \(2,3\) 的段。所以有用的段长只有 \(2,3,4,5\),所以有用的色彩值也很少。拿 map 暴力 dp 出来然后做个后缀 min 就行了。
!6030
Tag & Difficulty
Tag: constructive, observation | Difficulty: 2400Sol
特判没有黑格子的情况。注意到想要把整个棋盘染黑,最后一次操作一定是选一个全黑的行覆盖在某一列上。所以构造出全黑的行一定是到达最终状态的必经状态。以这个状态为分界点算两部分的最优解。当有了全黑的行之后考虑最小可能步数是多少。在这个全黑的行产生之前全黑的列的数量显然不可能增加,而那些已经全黑的列被非全黑的行覆盖肯定是不优的,也就是前面的操作一定不会用一个非全黑的行覆盖一个全黑的列,所以最后这一部分的操作数一定是 \(n\) 减去全黑列的数量。
创造一个全黑的行则考虑枚举是哪个行。假设是第 \(i\) 行,那么第 \(i\) 列必须要有一个黑格,如果没有就必须先做一次操作在第 \(i\) 列。剩余就是拿这个黑格子把每个第 \(i\) 行的白格子染黑就行了,而且这总是可行的,先把第 \(i\) 列以外的白格子染上不会影响这个黑格子的存在性,最后如果 \((i,i)\) 是白的再染上 \((i,i)\) 就行了。所以操作数就是第 \(i\) 行的白格子数加上 \([\text{第 i 行没有黑格子}]\)。
两边加起来就是最终步数。
01.10
刚到家就开始摸了
520
Tag & Difficulty
Tag: observation | Difficulty: 1500(guess), 2100(prove)Sol
不妨假设 $w$ 是有序的。先把平方拆开,$\sum_{i=1}^n 2w_i^2$ 的贡献在任何一个方案里都存在,所以可以发现最优方案需要满足 $\sum_{i=1}^n w_{p_i}w_{p_{(i \bmod n) + 1}}$ 最大。对着样例盲猜一波直接贪心把能匹配的最大的那个匹配就行了,最后的方案大概长成 \((n) \to (n-1,n) \to (n-1,n,n-2) \to (n-3,n-1,n,n-2) \to \cdots\)。为啥这是对的呢?
进行数学归纳,对于一个长度为 \(n\) 的方案,它一定是从长度为 \(n-1\) 的一个方案再将删掉的那个元素从里面插进去得到的。令删掉的元素为最小值 \(w_1\),根据归纳假设 \(2 \sim n\) 的最优方案是按照上面的形式排列的,可以发现在这个形式下 \(w_2,w_3\) 一定是相邻的。然后考虑 \(w_1\) 插在某两个数 \(w_i,w_j\) 之间,答案的变化量是 \(w_1(w_i+w_j)-w_iw_j = (w_1-w_i)w_j+w_1w_i\)。当 \(i\) 确定的时候,因为 \(w_1-w_i\leq 0\) 所以 \(j\) 越小答案越大,所以 \((i,j)\) 一定会选能选的最小的二元组,即 \((2,3)\),而 \((2,3)\) 本身是相邻的所以这是可以做到的。这样就可以说明上面构造出的方案是最优方案了。
01.11
6103
Tag & Difficulty
Tag: number theory, observation, brute force(Method 1) / binary search(Method 2) | Difficulty: 2200(Method 1) / 2600(Method 2)Sol
Method 1:众所周知 \(\mu\) 前缀和并不是很大(EI 哥哥跟我说是 \(\tilde{O}(\sqrt{n})\) 的但是咋证呢),所以可以考虑打表把所有可能的答案直接打出来。具体地,从 \(1\) 筛前缀和筛到 \(10^9\),每一次出现一个位置的前缀和小于目前最小的值或大于目前最大的值,就把这个位置和这个值记下来输出。直接筛的一个问题是空间爆炸,但 \(\mu\) 和记录每个位置是不是质数实际上只要 3 个 bit,所以可以用 bitset,这样空间就 reasonable 了。
然而长度还是超限的,可以做一些优化:具体地,把位置序列进行差分可以有效减少答案,同时每个元素加入的时候,要么是之前的最小值减小 1,要么是之前的最大值增大 1,所以可以用 LR 记录。这样就可以卡到 45KB。
Method 2:
不妨假设 \(\mu\) 的前缀和数组是 \(S\),先得到 \(S\) 的 \(n\) 前缀里面的最大值和最小值,假设分别是 \(S_R,S_L\),那么能表示的恰好是 \([S_L,S_R]\)。在这个区间内的的所有值取值的计算可以考虑二分,假设 \(L<R\),在 \([L,R]\) 上二分。每次选一个 \(mid\),那么若 \(x < S_{mid}\),因为 \(mu\) 前缀和的相邻元素变化量至多是 \(\pm 1\),所以 \([L,mid]\) 中一定存在 \(x\);反之 \([mid+1,R]\) 里面一定存在 \(x\),所以可以正确二分。内嵌一个杜教筛算值就行。
01.12
6104
Tag & Difficulty
Tag: observation, greedy | Difficulty: 2400Sol
首先如果某个位置是好的,那么它下面的所有位置都需要被取。所以一个局面实际上可以用一个长度为 $n$ 的序列表示。同时在最右边加入一个空列,显然不会影响答案。从左往右考虑每一列,并考虑如何将它里面的好格子恰好清空。我们容易计算得到将这一列清空时,下一列被消去的元素数量的最小值和最大值,而因为这两列消去的元素个数和模 3 等于 0,所以第二列能够消去的元素数量的可能取值是在最小值和最大值之间的公差为 3 的等差数列,而且其中每一个数都可以通过简单地对方案进行调整得到。这样下一列的元素个数就可以得到了。如果下一列元素个数的最大值都小于 0,就意味着有几个无用的格子需要被消去,否则在此处消去无用格子一定不优,你总是可以把在这一列消去的格子通过在这一列取到更大的值并向后推这一个无用的消去。所以第二列的元素个数仍然是个公差为 3 的等差数列,而它们每个能够产生的第三列的影响还是一个等差数列。所以每一轮每个位置的元素个数都是一个等差数列,简单维护即可。
6375
Tag & Difficulty
Tag: number theory | Difficulty: 2100Sol
$$\begin{align*} \sum_{i=1}^n \frac{in}{\gcd(i,n)} &= n \sum_{d \mid n} \sum_{i=1}^{\frac{n}{d}} [\gcd(i,\frac{n}{d}) = 1]i \\ &= n \sum_{d \mid n} \sum_{p \mid \frac{n}{d}} \mu(p) \sum_{i=1}^{\frac{n}{dp}} ip \\ &= n \sum_{d \mid n} \sum_{p \mid \frac{n}{d}} p\mu(p) \binom{\frac{n}{dp}+1}{2} \\ &= n\sum_{T \mid n}(\sum_{p \mid T} p\mu(p))\binom{\frac{n}{T} + 1}{2} \end{align*}$$ 筛出 $\mu$ 之后枚举倍数对每个 $T$ 算出 $\sum_{p \mid T} p \mu(p)$,再对这个枚举倍数算出每个 $n$ 的答案。!2156
Tag & Difficulty
Tag: observation | Difficulty: 2200Sol
值域比较小引导我们使用较少数量的信息调整出所有可能的答案。特判 \(1\) 和询问点直接超过整个序列的和的情况,对于一个 \(x\),如果有一个位置前缀和是 \(x\) 则直接输出这个前缀,否则因为值域不超过 \(2\),一定存在一个前缀值是 \(x-1\)。考虑调整这个长度为 \(x-1\) 的前缀到一个为 \(x\) 的答案上。
假设这个前缀是 \([1,r]\)。如果 \(a_{r+1} = 1\) 则直接把右端点移动到 \(r+1\) 即可,否则如果 \(a_1 = 1\),则可以同时把左右端点向右移动 \(1\) 得到 \(x\)。否则把左右端点同时移动 \(1\) 并砍掉第一个位置,可以得到一个子问题,不断递归这个子问题得到最终是否有一个 \(x\)。当然如果没有找到 \(x\),也就意味着 \(r=n\) 了,这个时候可以发现每一个后缀和大于等于 \(x\) 的位置都不存在一个前缀值为 \(x\),也就确实没有 \(x\)。
加速这一过程需要观察到实际上其只关心 1 和 \(r\) 之后的第一个 1 元素,提前维护出这个值就可以简单 if-else 写出答案了。
!2155
Tag & Difficulty
Tag: observation | Difficulty: 2400Sol
删掉两个点集非空的限制,最后减去不合法情况。考虑一个合法点集划分 \(S,T\),其中 \(S\) 是团,\(T\) 是独立集。此时可以注意到 \(S\) 中每个点的度数都一定大于等于 \(T\) 中每个点的度数:这是因为 \(S\) 中每个点度数都至少是 \(|S| - 1\),而 \(T\) 中如果有一个度数为 \(|S|\) 的点,则 \(S\) 的每个点都跟它连了边。而当 \(T\) 中有一个点跟 \(S\) 里每个点都连了边的时候,可以把这个点再丢到 \(S\) 里去,这样 \(T\) 里每个点的度数都小于 \(S\) 里的度数了,且这个 \(S\) 一定是图上的最大团。这提供了一个算法以判断有没有解:按照度数排序并找到前缀最大团,如果剩下的点不是独立集则一定没解。否则我们找到了一组解。考虑通过这一组解拓展出其他解。
因为 \(S\) 是团,\(T\) 是独立集,所以不能同时把 \(S\) 的两个点丢到 \(T\) 里面,反之亦然。因此只有非常少量的可能。对于 \(S\) 选一个点丢进 \(T\) 的情况,只需要判断 \(S\) 中有多少个点度数为 \(|S| - 1\) 即可。而 \(T\) 中每个点的度数都一定小于 \(|S|\) 所以不可能出现只把 \(T\) 里面的一个点丢进 \(S\) 产生的合法情况。还有一种可能是 swap 两个点集中的点。这需要 \(T\) 中被 swap 的点的度数为 \(|S| - 1\),且 \(S\) 中被 swap 的点恰好是没连上边的那个点,check 它的度数是否恰好为 \(|S| - 1\) 即可。以上是所有可能的情况。
01.13
!3581
Tag & Difficulty
Tag: dp, observation | Difficulty: 2500Sol
考虑按 bfs 树上的层顺序 DP。一个暴力是设 $f_{i,j}$ 表示 bfs 上的某一层是 $i \sim j$ 时的最少连边数,那么此时必定不能存在大于 $j$ 的点到小于等于 $i$ 的点的边。选择的元素 $k$ 必须要满足不存在大于 $k$ 的位置连小于等于 $j$ 的位置,转移值就是中间缺了边的点数。首先这个状态数就爆掉了,但可以注意到转移实际上只关心 \(j\),\(i\) 上其实只有一个状态的限制。所以考虑把状态合并成 \(f_j\) 表示 bfs 树的前若干层是前 \(j\) 个点的最少连边数,转移还是一样的。但其实可以注意到:找到了最小的能转移的 \(k\) 之后,每个 \(p>k\) 都能转移,而且转移值就是 \(k\) 的转移值加上 \(p-k\),所以可以弄个差分数组状物来维护转移,这样可以做到 \(O(n+m)\)。
*3238
Tag & Difficulty
Tag: bitwise, constructive | Difficulty: 3000Sol
https://zhuanlan.zhihu.com/p/341488123似乎是一个很经典的算法,但我完全不懂……
奇偶并行计算。先把它们看成 \(N\) 个 1 位数,那么每个数就都已经算好了它的 popcount。然后考虑将 \(N\) 个数的答案通过将相邻的合并,变成 \(\frac{N}{2}\) 个数的答案,大概是 \(N\ \mathrm{and}\ 010101010101 + (N\ \mathrm{and}\ 101010101010) \mathrm{rightshift} 1\),这样就变成了 \(\frac{N}{2}\) 个位置的答案。再类似做可以得到 \(\frac{N}{4},\frac{N}{8},\cdots\),最后可以合并成一个数。
01.14
以为要干活就摸了
01.15
!3150
Tag & Difficulty
Tag: string, greedy, observation | Difficulty: 2700Sol
先考虑如何判断一个字符串是合法的。当栈顶的字符跟当前字符不相等的时候显然只能 push 左括号,但当它们相等的时候,现在可以选择 push 左括号或右括号,我该选哪个呢?选右括号看起来就更优一点(?)不妨假设现在是第 $q$ 个位置进行决策,栈顶跟它字符相同的是第 $p$ 个位置,这也就意味着 $[p+1,q-1]$ 是合法的。假设当前选择了左括号得到了一个合法方案,$q$ 匹配的是 $r$,$p$ 匹配的是 $s$,显然有 $r$ 在 $s$ 前面,且 $[q+1,r-1]$ 和 $[r+1,s-1]$ 都是合法括号序列,这样把 $q$ 跟 $p$ 匹配,$r$ 跟 $s$ 匹配仍然是一个合法方案。所以说右括号在匹配合法性上总是比左括号优。那么字典序最小的做法也就很显然了:从前往后贪心地看左括号能不能放,不能放就放右括号。看左括号能不能放一个有一个显然的暴力做法:直接把后面的部分做一次贪心如果合法就行否则不行,但这样复杂度是平方的。可以看到这个暴力做了很多无用的工作,考虑做一些预处理进行优化:预处理一个 \(f_{i,j}\) 表示从第 \(i\) 个位置开始找到一个最短的前缀 \([i,f_{i,j}-1]\) 使得这个前缀能够括号匹配,且 \(f_{i,j}\) 位置的字符恰好是 \(j\)。这个的构建跟子序列自动机比较像:首先 \(f_{i,s_i} = i\),否则要往后找的时候先找到 \(i\) 什么时候被匹配,显然它要在 \(f_{i+1,s_i}\) 位置被匹配到,然后把 \(f_{1+f_{i+1,s_i}}\) 拉过来就行了。这样进行 check 的时候,从栈顶到栈底遍历所有元素,然后每次跳这个 \(f\),如果最后跳到了一个位置且这个位置到最后的后缀可以构成合法括号序列,那么它就是合法的。然而这样只是优化了常数但还是很容易卡到平方。
进一步优化考虑:每一次进行 check 的时候在图上走过的路径只是相比于上一次 check 多加了一个开头的字符,那么如果能倒着跑是不是每次就只需要在最后一个点的后面做一次转移就可以了呢?那么我们首先要验证倒着跑的正确性。倒着跑相当于每次在栈里面加入一个字符 \(c\) 的时候,从末尾往前看,找到第一个位置 \(p\) 使得 \(s_p=c\) 且 \([p+1,n]\) 都被匹配了,然后把 \(p\) 跟 \(c\) 匹配。尽管我们之前所证明的是 \(c\) 的匹配括号尽可能往左总是合法的,没有说尽可能往右也是合法的,但是我们仍然可以证明这样是对的。具体考虑 \(c\) 在贪心与左边字符匹配的情况,假设匹配到了 \(s_x\),而 \(s_p\) 跟 \(s_q\) 匹配,那么中间的三段都是合法括号序列,因此换成 \(xq\) 匹配也是合法的。这样贪心选择靠后的括号也是正确的。
这样我们从后往前建立一个与上面 \(f\) 类似的一个自动机,每一次 check 的时候就从上一次 check 到达的节点往后转移一个看合不合法,而每一次出栈就在自动机上回退一步。
01.16
**3147
Tag & Difficulty
Tag: tree, bitwise, binary search, constructive, observation, complexity analysis | Difficulty: 2600(construct), 3000(prove)Sol
Method 1:这个是官方标算,我当时在想:\(1625\) 次应该是 \(2 N \log N - O(N)\) 吧,结果看了看标算 \(3 N \log N - O(N)\)……
因为相邻的两个点同时出现在询问两侧这次询问就没意义了,所以可以首先把每个连通块打包成一个大点,给它们进行编号。先定位新连的边所连接的大点编号,设现在有 \(S\) 个大点。操作次数与 \(\log\) 相关,除了二分以外我们还可以想到位运算定位。基于位运算我们很容易想到一个子过程:按照编号的第 \(k\) 位分成两个集合 \(S,T\) 并询问它们,如果答案是 1 意味着最后连接的两个大点编号的异或的第 \(k\) 位是 \(1\)。这样做 \(\log S\) 次之后定位出 xor,那么每个大点就至多唯一对应另一个大点,在这些 pair 里面二分出真正连边的 pair,这里的操作次数是 \((\log S) - 1\)。
最后已知大点的情况下找到连接的小点就直接在两个连通块点集上二分就行了,需要注意的是这里的复杂度上界,看似这里总共会花费 \(2 N \log N\),但实际上只会花费 \(N \log N - O(N)\)。我们可以依据合并的结构建立一个重构树,那么二分的总代价是子树大小 log 的和,也就是子树大小乘积的 log。如何把这个东西卡到最大呢?实际上一条链就是最大的,这可以很容易地归纳证明。这个时候的花费是 \(\log N! = \sum_{i=1}^N \log i = N \log N - O(N)\)。
最后,设 \(T = \log N! = N \log N - O(N)\)(这个 \(O\) 大概是 \(\frac{1}{2} \sim 1\) 的样子),总操作次数是 \(3T - N\),但官方题解说卡不满……
Method 2(我没实现过但感觉挺对):
还是跟上面大点的想法一样,考虑做一个并行的二分:把大点集合随机均分成两半 \(P,Q\) 查询,如果里面有答案了就直接在里面二分,否则答案一定在两个集合内部。把分裂出的两个集合再分别均分成两个 \(P_1,P_2,Q_1,Q_2\),然后查 \(P_1 \cup Q_1\) 和 \(P_2 \cup Q_2\),如果有就直接在它们上面二分,否则再把这四个集合均分成八个再查询。在期望意义下只要交互库是 non-adaptive 的,一次询问的操作次数似乎是 \(\sum_{i=1}^{\log N}\frac{i}{2^i} = 2 - o(1)\) 的。最后两次二分是 \((\log N) - 1\) 的,所以毛估估是 \(2 N \log N\)
3151
Tag & Difficulty
Tag: dp | Difficulty: 2300Sol
一个显然的 dp 是 $f_{i,j}$ 为长度为 $i$ 的前缀分成 $j$ 段的最小分数。设 $cnt(p,q)$ 表示 $p$ 到 $q$ 都全对的人数,$sum_k$ 表示前 $k$ 题的分数和,那么 $f_{i,j} = \min_{k=0}^{i-1} f_{k,j-1} + cnt(k+1,i)(sum_i-sum_k)$。按照 $j$ 从小到大转移,注意到 $cnt(k,i)$ 只有 $N+1$ 种可能的取值,枚举每种取值,合法的 $k$ 的范围是一段区间(实际上将其看成一段前缀也是可以的,因为前缀的 $cnt$ 必定是更小的,而将更大的值算进答案显然不会影响最小值,而看成前缀写起来更简单),那么只需要维护前缀的 $f_{k,j-1} - csum_k$ 的最小值就行了。同时这个合法前缀的长度一定在变大(这是因为左端点固定时右端点移动 $cnt$ 一定是不增的,而右端点固定左端点向右 $cnt$ 一定不减),所以用单调指针维护就可以了,复杂度 $O(NST)$。3589
Tag & Difficulty
Tag: data structure | Difficulty: 1700Sol
假设一个询问是 $(p,q)$,那么走弹弓 $(x,y,t)$ 的时长是 $t+|x-p|+|y-q|$,把绝对值拆开之后就变成了二维偏序,离线扫描线线段树即可。3590
Tag & Difficulty
Tag: tree, data structure, observation | Difficulty: 2200Sol
重要的结论:在一棵树上,到某个点最远的点一定是其直径两端点之一。因为询问可以离线,所以先把树结构建出来弄个树剖支持算两点距离,然后在动态加点的过程中维护每个连通块的直径。每当一个点加入的时候,新的直径端点只有可能是当前点与原本直径的两端点这三个点中的两个,查询一下三种距离取最大值即可。!3591
Tag & Difficulty
Tag: number theory, counting, observation | Difficulty: 2100(guess), 2800(prove)Sol
发现输入只有一个数果断打表(实际上我也不想打表,但是不打表在旁边干想了很久都不会 TAT),对 $N = 1 \sim 9$ 的合法方案进行观察可以发现一些有用的性质:一是序列中最大值一定至多比最小值大 $1$;二是最大值比最小值大 $1$ 的时候整个序列一定有循环节,且循环节长度一定是序列最小值和 $N$ 的 $\gcd$(最小循环节可能是它的约数),而且在这个情况下单个循环节里的每个非空非全集都可以选择变成最大值,而补变成最小值(比如 $N = 9$ 的时候形如 $667667667$ 的有六种,就是选前三个的一个非空非全集变 $7$ 其他都是 $6$)。满足这些条件的数列恰好是打表中出现的数列,但这是为什么呢?首先我们需要说明这样的数列确实都是满足题意的。首先所有元素都相等的数列显然是合法的,现在考虑将所有元素都相等的数列中的某一个元素加一,考察序列需要至少发生怎样的变化(这个是比较重要的直觉,就是上面打表得到的数列一定是所有元素相等的数列不断将某些元素加一之后得到的,所以用这样的策略进行接下来的分析)。不妨假设所有元素都是 \(x\),你选择给 \(a_i\) 加一,那么根据题目条件 \(a_{i+x}\) 也要对应加一,\(a_{i+2x},a_{i+3x}\) 依此类推,下标对 \(N\) 取模,直到最后回到 \(a_i\) 就停下来了。根据基本的数论知识,这样遍历会遍历到模 \(\gcd(x,N)\) 同余的下标里的所有元素。这说明了为什么最大值比最小值大 \(1\) 的时候循环节一定是 \(\gcd(x,N)\),且通过这样的构造,我们可以将所有满足上面发现出的性质的序列构造出来,也就是它们都是合法的,而其他最大值比最小值大 1 的都一定不合法。
同时还需要说明不存在最大值比最小值大 \(2\) 或者更多的序列是合法序列。假设现在有一个最大值比最小值大 \(1\) 的序列,然后你现在选择把一个最大值 \(a_p\) 加一。现在 \(a_{p+x+1}\) 就会顺势加 \(1\)。那么现在有两种可能:一是 \(a_{p+x+1}\) 是最大值,那么继续往后做 \(a_{p+2x+2}\);另一种情况是 \(a_{p+x+1}\) 实际上是最小值。那么它下一步的步长会变成 \(x\),然后 \(a_{p+2x+1},a_{p+3x+1},\cdots,\) 最后一定会再回到 \(a_{p+x+1}\) 然后再以步长 \(x+1\) 往后跑。又因为步长 \(x+1\) 的时候一定会遍历模 \(x\) 下的所有同余类,所以最后所有的最小值都会被顶上来,得到的序列仍然是最大值比最小值大 1 的,也就是说不可能存在最大值比最小值大 \(2\) 的序列。
因此答案就比较简单了,枚举最小值 \(x\),特判 \(x=N\),答案是 \(1+\sum_{i=1}^{N-1} (2^{\gcd(i,N)} - 1) = 1+\sum_{d \mid N,d \neq N} \varphi(\frac{N}{d})(2^d-1)\),质因数分解后暴力枚举因数计算即可。
01.17
*3152
Tag & Difficulty
Tag: divide and conquer, data structure, constructive, observation | Difficulty: 3100Sol
先考虑一些简单的构造,假设中间节点之间不能互相连,那么 in 和 out 的个数乘积不能超过 $10^5$,一个很显然的想法就是 $316 \times 316$,于是把两边的点按 $316$ 个分一份然后两两之间建一个点连边就行了。这样可以过前五个 sub。然后我先考虑了些这个意义上的简单拓展:可以把块长放到大于 \(316\),比如说是 \(317\),那你可以 in 所有点连 out 前 \(315\) 个点,然后 in 里删一个点 out 里加一个点,最后 in 里再删一个 out 把最后那个加上。如果块长是 \(X\),这样大概用 \(2X\) 的完成了 \(\sum_{i=1}^n \min(X,\frac{P}{i})\) 次连接,但是仅仅从每条边的平均利用效率看过 sub6 都不行,更何况这样的分配实际上还是比较困难的。
然后我就去睡大觉了,第二天醒来想了想:我要做的大概是每次 in 里选个区间 out 里选个区间连上,那么我优化能不能考虑区间连边的优化呢?然后就想到了线段树。能否把之前的分块做法结合上线段树做呢?这实际上是可行的。
具体地,对于 316 个点建立一棵用于优化连边的线段树,因为两边是类似的,这里我们只考虑 in 部分构成的线段树。每次连边的时候,树上每个点能够到达的 out 点数量就会加上 316,这个时候有一些点的 in 乘 out 就会超过 \(P\),把这些点到树根的链并进行重构就可以了。这样跑出来大概只要 6w 条边,完全可以通过。
但是这个做法好像还是没有很强大的 intuition,有没有哥哥教教啊(感觉一个 intuition 是想办法让一块每次连出去的时候信息能复用,于是想到用小的拼出大的这样每次只有大的要换,然后就是线段树?)
3577
Tag & Difficulty
Tag: divide and conquer, brute force, data structure | Difficulty: 2500Sol
初始答案就是一个逆序对,然后对于每一次交换都需要计算一个形如 $C(i,j)$ 表示抽出序列中的 $i,j$ 之后正序对个数减去逆序对个数的值。这东西看起来除了暴力扫没有更好的做法,同时总出现次数和比较小,所以考虑一个根号分治。设块长 $B = \frac{N}{\sqrt{Q}}$,对于出现次数大于 $B$ 的元素维护一个前缀出现次数的数组,这里复杂度 $O(\frac{N^2}{B}) = O(N\sqrt{Q})$。对于每组 $C(i,j)$ 的询问,如果 $i,j$ 的出现次数都小于等于 $B$ 就暴力,复杂度 $O(QB) = O(N \sqrt{Q})$。否则假设 $i$ 的出现次数更多,则暴力枚举 $j$ 的每个出现位置在 $i$ 的前缀出现次数的数组上查询,对于每个 $i$ 把所有询问过的 $j$ 的答案记忆化下来。这样对于每个出现次数大于 $B$ 的元素只会扫 $N$ 次,复杂度 $O(\frac{N}{B}N) = O(N \sqrt{Q})$。!3201
Tag & Difficulty
Tag: binary search, geometry, brute force | Difficulty: 2600Sol
首先,一次 query(a,b,c) 相当于知道 $c$ 在 $a \to b$ 的右半平面还是左半平面。考虑增量维护顺时针的凸包,那么这个凸包就是顺时针存储的所有有向直线的右半平面的交。那么新加入一个点,如果它在凸包上,它一定会在凸包上连续一段有向直线的左半平面内,且有 \(k\) 条这样的有向直线,就有 \(k-2\) 个点要从凸包里删掉。所以如果能够找到一条在左半平面的凸包上的有向直线,接下来暴力拓展两边然后对凸包进行加删就可以了,复杂度是对的。
现在问题变成了找一条满足条件的直线。看到操作次数与 \(N\) 的关系很自然地想到在凸包上做一个二分查找。而询问一次跟半平面分割有关,那么很自然地想到一个算法:找到凸包的一条弦使得其分割的两边的点数的最大值尽可能小,然后查询给出的点在这条直线的哪一侧,然后把另一侧凸包上的点丢掉得到一个新凸包。最后可以递归到一个三角形,然后暴力即可。
它的正确性是容易描述的,只需要考虑给出的询问点在凸包内或者凸包外的情况。原来的点在原凸包内部的时候,因为保留的是以分割直线为基准同侧的凸包,它一定也在新凸包的内侧。而如果原来的点在凸包外,新的点显然也在凸包外,只需要考虑在新的凸包找到的对应左半平面的凸包上有向直线确实在原来的凸包上就行了。这只需要考虑最新加入的分割直线,而以分割直线为基准凸包和新加入的点在同一侧,所以它一定不会作为新凸包的答案。这样这个算法就是对的了。
实现上,二分的时候总可以让凸包上的某一个基准点作为分割直线穿过的点,这样就变成序列上二分了。同时加删可以直接用 vector 暴力,想想普通平衡树 vector 怎么草过就很正确了。
01.18
2426
Tag & Difficulty
Tag: graph, constructive | Difficulty: 2000Sol
如果图上存在一个点的连通块显然答案是 NIE,否则对于每个连通块进行染色,黑点和白点选不同的工会即可。2427
Tag & Difficulty
Tag: brute force, hashing | Difficulty: 1800Sol
暴力枚举分段长度 $k$,总段数是 $O(n \log n)$ 的,所以只需要快速计算本质不同的段数就可以了,这可以进行一个字符串哈希之后用 set 简单实现。2449
Tag & Difficulty
Tag: graph, observation, greedy | Difficulty: 2800Sol
01.19
今天帮 pb 审员交 PPT 了所以摸了
2614
Tag & Difficulty
Tag: number theory, observation | Difficulty: 2100Sol
模十有关的因子是 2 和 5,考虑先算出 2 和 5 各自出现的次数(值得注意的是 5 总是比 2 少),然后算出除去所有 2,5 因子之后所有数的乘积的最低位的值,最后把两边的答案合并起来。前者的计算是容易的:设 \(f(n,k)\) 表示 \(n!\) 中质数 \(k\) 作为因子的指数。计算时先考虑把 \(k\) 的非倍数剔除掉,剩余 \(\lfloor \frac{n}{k} \rfloor\) 个数都贡献了至少一个 \(k\),而把 \(k\) 除掉之后又变成了 \(f(\lfloor \frac{n}{k},k)\)。所以总数就是 \(\sum_{i \geq 1} \lfloor \frac{n}{k^i} \rfloor\)。
后者使用类似的方法做:设递归过程 \(F(n)\) 表示去除 \(2\) 和 \(5\) 的因子之后 \(n!\) 的末位,则先把所有奇数提取出来,这一部分构成的是 \((n - [2 \mid n])!!\),你需要求它的把 \(5\) 的因子提取出来之后的答案末尾;而偶数部分把 \(2\) 除掉又是一个阶乘,递归到 \(F(\lfloor \frac{n}{2} \rfloor)\)。为了前面提到的奇数部分的计算,又设递归过程 \(G(n)\) 表示计算 \((2n+1)!!\) 剔除所有 \(5\) 的因子之后的乘积的和。还是类似先把所有 \(5\) 的倍数提取出来递归,而对于非 \(5\) 的倍数,每一个 \(1,3,7,9\) 的段的贡献一定是 \(9\),所以对于完整的段贡献容易计算;而对于最后一个可能缺一些元素的段,如果最后一段有 \(5\) 就把可能缺失的对应的 \(7,9\) 填上成整段(在模 \(10\) 意义下它们有逆元所以乘上逆元就填上了),否则把多出来的 \(1,3\) 贡献到答案里面。注意如果最后一段有 \(5\) 不能直接认为 \(5\) 的贡献是 \(1\) 然后把这段删了,不知道我最开始写的时候怎么想的(
而且今天见识到了 python 的双星号操作符竟然没有快速幂((
01.20
3258
Tag & Difficulty
Tag: binary search | Difficulty: 1400Sol
罚款最大值是 $f_i$ 的时候每条道路都会选择卡到上限,最后如果没有跑完就在终点歇一会儿就行了。所以对每个 $f_i$ 算出每条道路速度都达到 $f_i$ 罚款的上限的时候通过的时间,每组询问在上面二分一下就行了。3259
Tag & Difficulty
Tag: data structure | Difficulty: 2200Sol
对于每个区间中的每种数字,认为只有第一个数字有 1 的贡献,其他的贡献是 0。也就是说如果区间中的某个数在它之前有一个一样的数,那么它不对区间数字个数产生贡献。显然这样转换贡献不会影响答案。然后考虑序列中每个元素对每个区间长度的答案贡献。考虑第 \(i\) 个元素,假设最靠近 \(a_i\) 的前面一次出现是 \(a_p\),如果不存在 \(p=0\)。那么长度为 \(l\) 时,左端点在区间 \([\max(p+1,i-l+1) , \min(i,n-l+1)]\) 内第 \(i\) 个元素产生 \(1\) 的贡献,贡献量就是这个区间的长度。可以发现这个区间长度的改变量不会超过 1,且每一次改变量的改变发生在 \(\min,\max\) 的切换或者区间长度变成 \(0\) 的地方,这意味着将贡献二次差分之后每个元素只会对常数个位置产生影响。按照上面的计算方式对应修改之后两次前缀和就可以得到答案。
01.21
3262
Tag & Difficulty
Tag: counting | Difficulty: 2300Sol
首先可以发现 $a,b,c,d$ 都必须小于 $n$,否则 $ab-cd = a(b-d)+d(a-c)$ 一定会大于 $n$。然后对着前面那个拆开的柿子看了看有个不太好写的 $n^2 \log n$ 做法,结果换个思路直接有 $n^2$:(枚举 \(c,d\) 的取值,先忽略 \(a>c,b>d\) 的限制计算答案。这个实际上是非常简单的,只需要把所有 \(ab\) 的可能答案放桶里就行了。然后容斥 \(a>c,b>d\) 的限制,因为这两个限制不可能同时违背,而且 \((a,c)\) 和 \((b,d)\) 是本质相同的,所以可以只容斥一边然后乘 2。假设这里容斥的是 \(a>c\),那么从小到大枚举 \(c\) 的取值,把所有 \((a \leq c,b)\) 对应的 \(ab\) 放进桶里然后枚举 \(d\) 算容斥贡献就行了。
3263
Tag & Difficulty
Tag: binary search, complexity analysis | Difficulty: 2200Sol
考虑过程 $\texttt{solve}(x)$ 表示找 $0 \sim x$ 的最优解。如果 $x=0$ 答案显然是 $0$,否则考察小于等于 $x$ 的最大的面值 $a_i$。那么根据拿多少张 $a_i$,$0 \sim x$ 可以被分为 $0 \sim a_i-1,a_i \sim 2a_i-1,\cdots,\lfloor \frac{x}{a_i} \rfloor a_i \sim x$。除了最后剩下的一段之外,前面的所有段在拿完 $a_i$ 之后都是一样的询问 $0 \sim a_i-1$,所以只有最后一个整段有用,它的答案可以递归调用过程 $\texttt{solve}(a_i-1)$ 得到。而对于最后一个段,它递归到的是 $\texttt{solve}(x \bmod a_i)$。从这两个部分取最优解即可。很显然这个递归过程可以同时进行最优解的取钞票总和的计算。每一次 \(\texttt{solve}\) 只需要用二分找到 \(a_i\) 复杂度是 \(\log n\),所以只需要分析 \(\texttt{solve}\) 的运行次数。对询问过的值记忆化一下可以发现:除了 \(\texttt{solve}(a_i-1)\) 以外,每一组询问的递归模式都形如 \(x \to x \bmod a_i \to (x \bmod a_i) \bmod a_j \to \cdots\),同时由于每一个取模都确实让值减小了,容易发现每一次都一定让值减小了至少 \(\frac{1}{2}\)。这样总递归次数不会超过 \(O((n+q) \log V)\)。
3264
Tag & Difficulty
Tag: matrix, data structure | Difficulty: 2200Sol
有用 $(+,\max)$ 矩阵描述 dp 然后用线段树动态维护的做法,但我写的不是这个玩意。考虑用线段树维护整个序列,那么对于一个区间来说,与其他区间合并实际上只关心这个区间从左端点往右的连续最长的举海报段和从右端点往左的连续最长的举海报段,所以线段树上一个节点只需要 \(4 \times 4\) 的信息量。合并的时候可以先对某一个节点做前缀 \(\max\),这样就可以 \(4^3\) 合并。对于覆盖区间长度较小的点合并起来有一些边界,一个好写的做法是线段树建立到长度 \(\leq 8\) 的节点就不往下建了,每次修改的时候找到对应的长度 \(\leq 8\) 的点然后 \(2^{\texttt{len}}\) 重建。不知道为什么现在跑到了 rk1.
01.22-01.25
《打了四天摆,抽了点时间出来写点水题水博客度日》
3025
Tag & Difficulty
Tag: data structure | Difficulty: 2000Sol
考虑一个空闲的电梯在第 \(T\) 个时刻接到了第 \(A\) 层的信号并进行处理,那么它会在 \(T+2(A-1)\) 层完成这个信号的响应并到达一层。反推一下,它会在 \(T+2(A-1)-1\) 时刻把二层的所有人接走,\(T+2(A-1)-2\) 时刻把三层所有人接走……把接走的人的 \((T,A)\) 坐标放在平面上,那么一次电梯会接走的人是一个四十五度的直线与一个平行于 \(x\) 轴的线(要限制不能接到大于 \(A\) 层的人)的半平面交里面,把 \(T\) 换成 \(T+A\) 之后就变成了个二维偏序,每次拿走一个左下矩形里面的所有点。看起来要一个二维数据结构,但是每个点只会被拿走一次,所以可以每个纵坐标弄一个 deque 从前往后维护所有点,然后再拿个线段树维护一下每行的最靠前的点坐标,每一次 query 一个行的前缀查一下列最小点,如果它在矩形内就删掉更新线段树。
3026
Tag & Difficulty
Tag: tree, dp, string | Difficulty: 2100Sol
由于树的递归性质很容易想到使用 dp 解决。设 $f_{i,j}$ 表示将 $i$ 点子树里的所有边用模板串覆盖且向上至少延伸到深度为 $j$ 的点 $(j \leq dep_i)$ 使用的最小代价。因为深度越浅总是越优的,所以这里设成至少不会影响答案,而且这样会比较方便转移。考察其如何从子树转移过来。设 $mnf_i = \min_{j=0}^{dep_{fa_i}} f_{i,j}$。枚举延伸深度最浅的那个覆盖串从哪个地方过来。如果从自己来,则枚举这个深度 $k$,先考察这一段的模板串权值,这个将所有模板串倒着插在 Trie 里然后从深往前枚举 $k$ 在 Trie 上走就可以了,而所有儿子一定都会选择 $mnf$ 作为转移值。如果从某个儿子来,枚举这个儿子向上延伸的深度,其他子树则从 $mnf$ 来。对于每个值维护一下它从哪个地方转移过来并额外维护 $mnf$ 取到的位置容易还原方案。3027
Tag & Difficulty
Tag: greedy, brute force | Difficulty: 1300Sol
枚举文本页的数量 $i$,那么首先在前 $k$ 页是插图页剩下 $i$ 页是文本页的页码和最小情况下页码不能超过 $S$。其次考虑还需要至少加入多少插图页才能取到 $S$。注意到对每个新插图页决定将其放在多少个文本页之前,它可以对答案产生 $[1,i]$ 中任意一个数的贡献,且任意两个新插图页的贡献是独立的,这意味着加入 $p$ 个插图页可以组成 $[0,ip]$ 中的任意一种答案贡献的增量。所以新增的插图页数量的最小值就是 $\lceil \frac{S - ki - \binom{i+1}{2}}{i} \rceil$。注意到最小页码数里有个 $\binom{i+1}{2}$,所以 $i \leq \sqrt{2S}$,这样枚举的复杂度是 $O(\sqrt{S})$。3028
Tag & Difficulty
Tag: tree, greedy, observation | Difficulty: 1700Sol
不妨先考虑 $T_2$ 的答案跟 $T_1$ 有什么关系。首先 $T_2$ 的直径一定会经过原始 $T_1$ 上的由两个叶子之间的路径(如果直径没有经过叶子,那么 $T_2$ 必定在延伸出的一个 $T_1$ 中,它一定不比原始的 $T_1$ 的直径延伸出的路径优;而只经过一个叶子结点的话,在 $T_1$ 里的端点显然可以延伸),那么这个直径一定形如 $T_2^\star \to T_1 \to T_2^\star$ 的结构(这里这个 $T_2^\star$ 表示的是新加的点)。其中 $T_1$ 的最长路就是直径,而 $T_2^\star$ 的路径一端点已经确定为 $1$,想路径长度取到最大必定取 $1$ 开始的最长路。同时可以发现这三者可以同时取到最大值,所以 $T_2$ 的直径长度就是 $T_1$ 的直径长度加上两倍 $T_1$ 上 $1$ 开始的最长路长度。可以发现上述讨论可以延伸到任意 $T_x \to T_{x+1}$,所以每次的增量是相同的,乘一下 $(m-1)$ 就行了。3029
Tag & Difficulty
Tag: tree, dp, observation, data structure, complexity analysis | Difficulty: 2600Sol
可以发现所有合法区间恰好是 $[0,2^k-1]$ 的线段树上的每个区间,它们构成了一个树的结构。树结构自然地想到利用递归性质进行计算优化。首先可以分析一下问题的性质:如果两个区间互相包含且都染了色,那么长区间的染色时间一定比短区间早,否则短区间的染色没有意义。同时存在最优方案使得最长的区间一定被染过色:如果没有,可以把所有染色区间中最长的那个的颜色拿到这个整区间上,这样一定不劣。同时如果某个节点没有染色,可以认为其用了 0 的代价获得了其父亲染的颜色(当然如果父亲也没有颜色就再从更高的祖先上走,因为根节点一定有颜色所以这样总是能做)。因此可以考虑 dp:\(f_{i,j}\) 表示线段树上点 \(i\) 的子树满足条件,其中根染的颜色是 \(j\) 的情况下的最小操作次数。转移枚举两个儿子,有 \(f_{i,j} = 1 + \min_{p,q} (f_{\text{left child}, p} - [p=j]) + (f_{\text{right child, q}} - [q=j])\)。
可以发现 min 的两部分是独立的,同时由于转移系数只有 \(0\) 和 \(-1\),这意味着 \(f_{x}\) 数组中只有最小值是有意义的。维护最小值的下标 \(S_x\) 和最小值 \(v_x\),那么如果 \(S_{\text{left child}} \cap S_{\text{right child}} \neq \varnothing\) 则 \(v_i = v_{\text{left child}} + v_{\text{right child}} - 1, S_i = S_{\text{left child}} \cap S_{\text{right child}}\),否则 \(v_i = v_{\text{left child}} + v_{\text{right child}} - 1, S_i = S_{\text{left child}} \cup S_{\text{right child}}\)。边界状态则在所有位置颜色都相同的线段树节点上,它的 \(v = 1 , S_i = {col}\),其中 \(col\) 就是大家一样的颜色。对于线段树上边界状态以外的节点不去显式建立它们,这样线段树上的节点数就是 \(O(nk)\) 的。
在 dp 的具体实现的时候我们暴力枚举 \(S_{\text{left child}}\) 计算它们的交和并,这样的复杂度实际上是正确的。这是因为暴力合并的操作数不会超过每种颜色的所有目标区间在线段树上对应到的所有区间的链并的节点数,而每加入一个目标区间这个链并增加的节点数不会超过 \(k\)。用 set 的复杂度就是 \(O(nk \log n)\)。
3473
入门题,不写了
3474
Tag & Difficulty
Tag: ternary search | Difficulty: 1400Sol
这个 $\max$ 值显然对于分割位置是单谷的,所以对行列分别三分,计算答案可以通过 $\sum_{i=1}^n i = \binom{i+1}{2}$ 简单做划分行的情况,而分列的情况计算可以考虑:在第 $i$ 行减去 $(i-1)m$ 之后每行都是一样的,所以做若干次连续自然数和就可以了。一个比较好写的写法是用函数参数带进两个二分里面。3477
入门题,不写了
01.26
ROIR cleared
3479
Tag & Difficulty
Tag: randomization, observation, constructive | Difficulty: 2800Sol
先考虑 $c=2$。对于一个 $n \times m$ 的问题我们可以简化成:你需要取 $S_1,S_2,\cdots,S_n$,它们都是 $U = \{1,2,\cdots,m\}$ 的子集,表示颜色 1 对应的列编号。那么条件是 $\forall i \neq j, |S_i \cap S_j| \leq 1, |S_i \cup S_j| \geq m-1$,后者是因为颜色 2 的下标交也不能大于 1。不妨假设 \(n \leq m\)。\(n \leq 2\) 的情况是简单的,接下来考虑 \(n \geq 3\) 的情况。不妨假设 \(|S_1| \leq \lfloor \frac{m}{2} \rfloor\),否则交换两个颜色仍然是合法方案且满足该条件。那么 \(S_2,S_3\) 需要满足 \(|S_2 \cap (U - S_1)| \geq |U - S_1| - 1 , |S_3 \cap (U - S_1)| \geq |U - S_1| - 1\)。当 \(|U - S_1| \geq 4\) 的时候这两个条件可以推出 \(|S_2 \cap S_3| \geq 2\) 不合法,这意味着当 \(|U - S_1| \geq 4\) 的时候不可能存在合法情况。而 $ |U - S_1| \lceil \frac \frac{m}{2} \rceil$,因此当 \(m \geq 7\) 的时候不存在合法解。现在考虑 \(m = 6\),我们很容易通过上面的方法或者写一个暴力得到解:\(S_1 = \{1,2,3\},S_2 = \{1,4,5\},S_3 = \{2,5,6\},S_4 = \{3,4,6\}\),可以解决 \(n \leq 4, m \leq 6\) 的情况。
那么还有一个情况是 \(n,m \geq 5\)。我们接下来说明 \(n=m=5\) 也不存在解:根据上面的讨论,此时 \(|S_1|\) 必须等于 \(2\),因此 \(\forall i \geq 2, |S_i \cap (U - S_1)| \geq 2\),且 \(|U - S_1| = 3\)。\(U - S_i\) 的大小大于等于 \(2\) 的子集有四个,且最多拿出其中三组同时出现在 \(S_i\) 中,因此 \(n \leq 4\)。这也就说明上面的构造对应了所有情况。
当然在 \(n=4,m=6\) 的情况下,也可以发现每列实际上对应的是所有 popcount 为 2 的数的二进制表示,这样就可以不需要写 magic table 了。
对于 \(c=3\) 分析起来就不那么容易了,但是如果我们找到了一个 \(n=m=10\) 的方案其他方案就都出来了,所以考虑整一些乱搞。先随机一个方案然后通过调整法得到一个合法解。具体地,对于每个位置 \((x_1,y_1)\),算出取 \(x_2,y_2\) 使得四个角同颜色的方案数,然后再枚举其他的颜色计算新的方案数,从中取方案数降低最多的那个位置换成降低最多的那种颜色。如果怎么换都没法更优就随机一个位置换成一个随机颜色。直到其满足条件输出。不过很奇怪的一点是我第一次跑 2s 就出解了,后面多跑了几遍 10s+ 都没出解,所以可能还是比较看 rp。
3480
Tag & Difficulty
Tag: counting, graph | Difficulty: 2500Sol
注意到在本问题中,每一列我们只关心它是否进位、是否需要进位、是否有零(因为不能有前导零),其他信息都是没有用的,而当前列是否进位与下一列是否需要进位必须一致。把是否有零的信息先丢掉,那么每列的信息量是 2,而且最终串在一起要对应满足,容易想到建立图论模型:设 $f_{i=0/1,j=0/1,k=0/1}$ 表示向前进 $i$ 位、向后找 $j$ 位、有无零的列数,设 $f_{i,j} = f_{i,j,0}+f_{i,j,1}$,那么建立一个两个点的图,$i \to j$ 连 $f_{i,j}$ 条边,在删掉无前导零的限制之后每一个列的排列方案对应了图上 $0$ 为起点 $0$ 为终点的欧拉路,这是因为最前面一列不能有进位、最后一列一定不能要进位。而这个欧拉路的第一条边对应着最前面一列,它不能有零。因此 \(f_{0,1} = f_{1,0}\) 必须存在,否则图上没有欧拉回路。特判 \(f_{0,1} = 0\) 的情况(注意此时 \(f_{1,1} > 0\) 则答案为 \(0\)),那么 \((0,1)\) 和 \((1,0)\) 在序列中一定是交错放置的。先枚举第一列是 \((0,0)\) 还是 \((0,1)\) 方便加入第一列没有零的限制。不妨假设第一列是 \((0,1)\),那么 \((0,1)\) 的排列方案是 \((f_{0,1} - 1)!f_{0,1,0}\),\((1,0)\) 的排列方案是 \(f_{1,0}!\)。然后考虑一条一条将 \((0,0)\) 和 \((1,1)\) 放进去。加入的第一个 \((0,0)\) 可以放在每一个 \((1,0)\) 的后面(注意整个序列之前的位置是可以放的,但是这里限制了 \((0,1)\) 是第一条边所以不能放在开头),第二个 \((0,0)\) 则可以放在第一个 \((0,0)\) 以及所有 \((1,0)\) 的后面,依此类推方案数是 \(f_{1,0}(f_{1,0}+1)\cdots(f_{1,0} + f_{0,0} - 1)\),\((1,1)\) 也是类似的。而对于 \((0,0)\) 在开头的情况,最开头的一条边必须要是 \(f_{0,0,0}\) 中的一条,剩下的部分跟上面类似,只是需要注意第一条 \((0,0)\) 之后也可以放边了。
最后整理一下大概可以得到非常简单的答案形式是 \(f_{0,1}(f_{1,0}+f_{0,0} - 1)! (f_{0,1}+f_{1,1}-1)! (f_{0,0,0}+f_{0,1,0})\)
3478
Tag & Difficulty
Tag: constructive, observation, greedy | Difficulty: 2000Sol
瞎写出奇迹!第一类好数很简单,只需要考虑能不能变成跟开头都一样,如果不行就开头加一。
对于第二类好数,注意到第二位以及之后的整个部分一定可以变成 \(9999\cdots999\) 所以在最终的结果中第一位一定不会变。那么只有两种情况:第一位不同和只有一位和第一位不同。前者容易对后面的部分跑第一类好数的方法做,得到一个数 \(S_1\),后者则根据 \(S_1\) 的结果进行一些分类讨论。
若 \(S_1 > S_2\),那么唯一有意义的就是变成 \(\overline{S_1,(S_2-1),S_1,S_1,\cdots}\),判断它能否做到即可。
若 \(S_1 = S_2\),则在之前的情况以外还有 \(\overline{S_1,S_1,S_1,\cdots,?,S_1,S_1,\cdots}\) 的情况。贪心地想这个问号一定会出现得尽可能靠前,而最前的位置就是 \(S\) 中第一个小于 \(S_1\) 的位 \(S_k\)。如果后面的所有都可以变成 \(S_1\) 就变,否则 \(S_k\) 加一,此时 \(S_k = S_1\) 的话最优的是让 \(S_{k+1}\) 变成 0 其他变成 \(S_1\),否则就是其他位变成 \(S_1\)。
若 \(S_2 > S_1 + 1\),那么唯一有意义的是变成 \(\overline{S_1,S_2,S_1,S_1,\cdots}\)。
而 \(S_2 = S_1 + 1\) 时除了 \(\overline{S_1,S_2,S_1,S_1,\cdots}\) 以外还有 \(\overline{S_1,S_1,\cdots,S_1,?,S_1,\cdots}\) 的情况,这个问号会尽可能靠后,而最后的位置就是 \(S\) 中第一个大于 \(S_1\) 的位 \(S_k\)。如果后面的所有都可以变成 \(S_1\) 就变,否则 \(S_k\) 加个 1,如果没有进位就把后面都变成 \(S_1\),否则最优的就是让 \(S_{k-1}\) 变大 \(1\) 然后后面都变成 \(S_1\)。
按照上面的情况跟第一位不同的情况取个最小值就可以了。
3475
Tag & Difficulty
Tag: greedy, observation, constructive | Difficulty: 1900Sol
最小的情况,用删除操作一定最优。一般情况下删除操作会让某个段的长度减 1,需要注意只有删长度为 $10$ 的幂或者 $1,2$ 的段能让字符串长度减小,还有一个需要注意的情况是将一个段长为 1 的段删去之后旁边两段可能会合并起来,所以枚举一下删的哪个段就可以了。最大的情况,用插入操作一定最优。一般情况下插入只能让长度加 1,特殊的情况是在一个长度很长的段中间插一个不同的字符可以将它分成两段,问题是分开的两个段的段长会是多少。假设当前长度是 \(L\),整数 \(k\) 满足 \(10^k \leq L < 10^{k+1}\),那么分开的两段的数字部分在压缩串里的贡献不会超过 \(2(k+1)\),但也不会小于 \(2k\)。能分成 \(2(k+1)\) 的情况当且仅当 \(L \geq 2\times 10^k\),这个时候对半分就行了。而 \(2(k+1)-1\) 的情况则是 \(L - 10^k \geq 10^{k-1}\) 的情况,插在长度恰好分出 \(10^k\) 的地方。而最后一种情况则是 \(L < 10^k+10^{k-1}\) 的情况,这种对半分也可以取到最优解。因此取对半分和减十的幂的情况取最优即可。短长度的边界需要稍微注意一下,但可以发现用这两个策略还是对的。
3476
Tag & Difficulty
Tag: graph | Difficulty: 2400Sol
假设中间每一段的段长确定了是 $L$,那么设每一条绳子的第一个节点左边的长度是 $l$,右边的长度是 $r$,那么这个绳子右边接的一定是左边长度是 $L - r$ 的绳子。我们连边 $l \to L - r$,那么一个合法的排列绳子的方案对应了经过所有边恰好一次的一条路径,也就是一条欧拉路。这样只需要 check 图上有没有欧拉路就可以了,记得判断图是不是联通的。然而可能出现所有 \(m\) 都等于 \(1\),也就是说 \(L\) 是可以自己选定的。将所有 \(l\) 从小到大排序去重得到 \(l_{1 \sim p}\);类似 \(r\) 从大到小排序去重得到 \(r_{1 \sim q}\)。考虑选定了一个 \(L\) 之后,\(\sum_{i=1}^q [\not\exists k \in [1,p], l_k+r_i = L] \leq 1\),否则不可能存在欧拉回路(有两个点出度大于入度)。因此设 \(x\) 表示最小的满足 \(\exists k \in [1,p], l_k+r_x = L\) 的 \(x\),则 \(x \leq 2\)。同时 \(r\) 下标越大的数一定对应 \(l\) 下标越大的数,所以这个式子里取到的 \(k\) 也必须 \(\leq 2\)。这样可以发现 \(L\) 只有四种取值:\(l_{1/2} +r_{1/2}\),每个都算一遍就行了。
01.27
看了一手 WC 题目
![WC T1]
Tag & Difficulty
Tag: constructive, tree | Difficulty: 3100Sol
[WC T2]
Tag & Difficulty
Tag: data structure | Difficulty: 3000Sol
01.28
2770
Tag & Difficulty
Tag: greedy, observation | Difficulty: 2000Sol
先考虑 $T$ 全是同一个字符的情况,此时在最优策略下 $S$ 中对应的那种字符一定不会被换成另一种,且另一种字符一定是能换就换不会更劣。这样可以得到一个贪心:每当另一种符号可以换掉的时候就换掉。这东西可以从左往右扫然后用一个栈来维护贪心完成之后的字符串结构。在 \(T\) 字符不同的情况下,把 \(T\) 的所有片段拿出来。那么相邻的两个片段边界的两个字符一定不能相等,否则两个段不可能不相等。这也就意味着每个片段之间是独立的,一个片段内做操作一定不能影响到其他段。每个段内分别算一次字符全相同的情况,如果全都合法才有可能合法。当然还没完,还有一种情况是:相邻的两个片段边界的两个字符和目标字符都不相等,也就是说这两个字符一定会有一个翻转,此时两个段就合起来了。所以说相邻的段边界的两个字符一定得等于目标字符,在这种情况下根据上面的贪心策略它们都不会翻转,所以段之间还是独立的。
2771
Tag & Difficulty
Tag: observation | Difficulty: 2000Sol
设 $L_i$ 表示给第 $i$ 个服务器投放程序的合法时间段使得 $1 \sim i$ 都可以安装上,$R_i$ 就是 $i \sim n$。显然 $L_1 = R_n = \mathbb{N}$,而 $L_{i+1} = L_i \cap [l_i,r_i]$,而 $l_i \in L_{i+1}$ 时 $[l_i-t_i,l_i-1]$ 都会变得合法。容易归纳发现 $L_i$ 和 $R_i$ 一定都是区间,而区间求交可以 $O(1)$ 做,最后 $L_i \cap R_i$ 的最小值就是答案。2772
Tag & Difficulty
Tag: dp | Difficulty: 2300Sol
设 $f_x$ 表示已知生成了 $x$ 克反物质的情况下最优操作序列能够得到的收益值。转移枚举下一次实验选择哪个,选择 $(l_i,r_i,c_i)$ 则需要保证 $x+r_i \leq A$,转移为 $f_x = \max(f_x , \min_{y \in [x+l_i,x+r_i]} f_y - c_i)$,初值 $f_x = 10^9 x$。容易发现需要快速进行的是一个半在线的滑动窗口,拿 $n$ 个 deque 弄弄就行了,然后 TLE 92pts。卡常可以把 deque 的每个元素弄成下标和值的 pair,这样可以避免数组内部乱序寻址,然后贴着时限卡过。01.29
打 USACO 去了,有数据了更
01.30
打 Goodbye XinChou 去了,被打爆了,没心情写题了(?)
01.31
正常人谁除夕写题啊