ZJOI2022 游记
Day -132
- CF1593F,2100,基础 dp。 注意取模时要除不一定有逆元,所以使用我为人人型 dp,并记录转移来的状态。
- CF1392E, 2100,构造。方案开始不同时让二进制上的一位只有一种能取到就不会有相同的和了。
- CF1389D,2100,暴力。分讨要仔细啊啊啊(好像是废话)。
- CF1372D,2100,思维。
- CF1387A, 2100, 思维。图上边权等于点权和的这类方程,没有高斯消元也是可以解出的。
- CF1364D,2100,图论。考虑完有环的情况也别忘了树啊(
- CF1363D, 2100, 二分。最大最小值问题很有可能有很多询问答案都是一样的。
- CF1360H,2100,二分。恶评题,根本没到 2100。
那我为啥还要调那么久
Day -131
题目概况/一句话题解
- CF1355E,2100,三分。设最终高度为 \(h\),要增加 \(X\) 减少 \(Y\),可以证明在当且仅当有 \(X>Y\) 时 \(h+1\) 更劣,是单峰函数。整数上点的三分可以判 \(mid\) 和 \(mid+1\) 并在边界缩小到一定范围时直接暴力做。
- CF1354E,2100,图论。1、3 不能连在一起,所以图得是个二分图,一边放 1、3。染色后 dp 求出一种 2 的分配方案后 1,3 随便放即可。
- CF1343E,2100,图论。等价于从 \(b\) 出发到两边。这种情况下若两边的最短路有超过一段的交(头上也算)则合并起来一定不会更劣。又因为分开后两段若没有取到最短那么取上最短肯定更优,所以直接枚举交的另一个端点即可。
- CF1333D,2100,暴力。冒泡排序这个过程肯定是最短的,因为前面不做掉后面也不可能一下做更多,那么直接求出最少步数和最多步数即可。
- CF1332E,2100,数学。容易发现有奇数/偶数的数量有一个是偶数就行。总共有奇数个时一定满足条件。是偶数个时式子是二项式定理去掉奇数次项的式子,去掉奇数次项用 \(-1\) 的幂就可以了。这里求快速幂可以用欧拉定理“当 \(\text{gcd(a, m)=1}\) 时 \(a^{\phi(m)} \equiv 1 \pmod m\)” 来优化。注意 \(0^0\) 得处理成 \(0\)。
- CF1322B,2100,位运算。考虑每一位,显然对于每一个数只有比这一位更低的位才可能贡献。对于每一个数,有两个区间可以使这一位上有值(恰好加到这一位,这一位和更高一位都有)才行,树状数组维护即可。注意数组别开小了,因为范围会比数的和要大。
- CF1312E,2100,区间 dp。若一个区间要合起来那肯定最后只有一个值,因为这个区间里每个数的个数都是固定不变的。那么直接 dp 的同时记下每个区间的这个值,然后直接 dp。
- CF1299C,2100,单调栈。两个数若后面一个小则肯定对这两个一顿操作。若有三个数 \(a, b, c\),若先操作 \(b, c\) 再操作 \(a, b\) 会比直接 \(a, b\) 优则 \(\frac{b+c}{2} < a\) 此时不如直接做三个的。三个以上的都可以视作三个的情况。所以暴力做法是对于每一个往后找到一段使它最小的。这个用单调栈维护,每次不断尝试合并区间就可以了。
- CF1296F,2100,图论。直接从小到大覆盖再判一遍是否合法。
- CF1284D,2100,哈希。随便分配一个权值把不和一个交的段的权值异或在一起,若在两边一样则行,否则不行。出错概率极小。
- CF1278D,2100,扫描线。将线段左端点排个序,扫过去,用
std::set
维护现有线段,每次加入时在其中找没有完全覆盖新线段的连边。因为连边方向确定,所以边不可能重复,连边超过 \(n-1\) 直接输出NO
。
Day -130
- CF1267K,2100,组合计数。显然做出来后把余数打乱是不会有相同的,所以只要余数打乱后合法就行了。那么从大到小决定这个余数放哪些,每次乘上这位能放的个数在除以到现在为止重复出现的次数就行了(相当于最后除以了个全排列)。至于最后一个不能放零,减去最后一位强制放零时前面的方案数即可。
- CF1271D,2100,dp。前面放不会有后面放来的优,在一个城堡时要派出士兵肯定优先守卫价值高的,所以直接 dp 就好了。
- CF1271E,2100,位运算。奇偶显然可以分开考虑。对于一个确定的值,算出现了几次只需把没有对齐的位加一加,再加上对齐的时候的答案就行。这个变大时加上的肯定不会超过少掉的,所以有单调性,可以二分。
- CF1266E,2100,暴力。显然(其实我看了好久都没发现)所有的优惠都会取到,所以直接把减掉的和应有的取 \(\min\) 就是答案。
- CF1265E,2100,期望。走到这里的步数期望 = 回去再走到这里的期望步数 + 直接走过来的。移项就可以得到递推式了。
- CF1263E,2100,线段树。序列确定时,从左往右维护待匹配的左括号个数,若中间有小于 \(0\) 的或最后不等于 \(0\) 直接不合法,否则中间的最大值就是最大嵌套层数。可以用线段树维护这个。
- CF1254B1,1800,暴力。肯定是分成一样的因数组,直接模拟分组。
- CF1254B2,2100,dp。受到 easy version 启发发现这个问题和前面那个本质没有区别,肯定还得分成总数的一个质因数(否则继续拆分肯定更优)组,每一个点若前面没法解决就往后推,所以对于每个点就可以知道有多少次要 移进/移除 了。
- CF1252G,2100,线段树。对于每一天,都得满足前面要踢掉的个数小于等于比“我”小的,那么就是和前面那个 CF1263E 差不多的问题了。
- CF1250C,2100,扫描线。枚举一个又端点,前面每个点的答案在右端点移动的时候就会减去 \(k\),然后再在新加入的线段左端点加入线段的贡献。可以用线段树维护。
- CF1223E,2100,dp。注意到这个限制其实就是限制一个点的出边最多有几条被选中,那么设 \(f(i, 0/1)\) 表示一个点为根的子树,不要/要 空出一个限制来的最大价值。然后对于子树,先看哪个大一点加进当前的状态,然后再根据给它一条边的增加量排个序依次加入即可。、
洛谷 remote judge 什么垃圾,一天出了四次问题了。
Day -129
- CF1252K,2100,矩阵乘法。\(a = a+b\) 和 \(b = b+a\) 都可以用矩阵来表示,反转一段实际上是把那一段矩阵乘起来的结果翻转了,用线段树维护矩阵即可。
- CF1217D,2100,dfs 树。环必须有返祖边参与,所以只要返祖边和其它边的颜色不一样就可以了。
- CF917A,1800,思维。维护当前未匹配的左括号的上下界即可。
- CF917B,1700,dp。根据题意搜索,然后记忆化。
- P5505,蓝,容斥。把都有转换成没有人没有,用 \(g(i)\) 表示恰好 \(i\) 人没有,\(f(i)\) 表示钦定 \(i\) 人没有,然后根据二项式反演把求 \(g\) 转换成求 \(f\) 后即可。\(f(n) = \sum_{i=n}^m{i \choose n}g(i) \Leftrightarrow g(n) = \sum_{i=n}^m(-1)^{i-n}{i \choose n}f(i)\)
- P6478,紫,dp。先用二项式反演转换后树形 dp。这两题都是为了学习二项式反演而做。
- CF917D,2600,dp。套路地用二项式反演转换后树上背包即可。一个结论: \(n\) 个点的 \(k\) 个联通块的生成树个数是 \(n^{k-2}\prod a_i\),然后这个 \(\prod a_i\) 又可以转换成每个里面取一个的方案数,于是背包时后面加一个当前块 取/没取过就可以了。一篇不错的题解。
- CF1213F,2100,哈希。上下两个集合一样则必须一样。判断集合用随机一个权值然后异或的哈希。
- CF1207F,2100,分块。按模数分块做,模数小的维护一个和,模数大的直接暴力做。这种看起来很 ds 又没啥想法的题不如试试分块。
- CF1204D2,2100,思维。如果把
1
看成(
,0
看成)
,那么如果一串组成了一个合法的括号序列,肯定是没法改变了。因为10
没法改变,若A
没法变,AB
也没法变,同时若S
是没法变的,可以归纳地证明1S0
改变左右都会使答案加一,所以也没法变。那么先从输入中抠掉合法的括号序列。发现剩下的全 \(0\) 一定不会使任何一段改变,因为括号序列的最长不下降子序列可以由0
构成也可以由1
构成。这题太妙了吧!谁想得到啊! - P7716,绿,计数。出现两次的放法是唯一确定的,出现一次的可以枚举四种看是否合法。没有出现过的只能放在两个都是比它大的下面,把放法数一个个都记下来然后搞个求 \(k\) 个数的积的和的 dp 就可以了。
- P4781,蓝,模板。\(f(x) = \sum_{i=1}^n y_i \prod_{j \ne i}\frac{x-x_j}{x_i - x_j}\)。
- P3143,绿,暴力。显然答案是排完序后的不相交两端,那用 二分/双指针 前后两个方向都做一遍就可以了,
- P2254,蓝,dp。因为时间只增长,所以可以有个三维的 dp。把其中的时间换成时间段,枚举改成可以到达这个的点。发现转移是要求前面一段的最大值,可以用单调队列或者优先队列来解决。
Day -128
在做一些月赛好题。
- CF1203F1,2100,贪心。可以分成两部分处理,一部分是 \(b_i\) 正的,一部分是 \(b_i\) 负的,正的的话直接按照 \(a_i\) 排序做就行,负的要满足本来没有前面的那个不行的有了前面的更优,即 \(\max(a_i, a_j-b_i) \le \max(a_j, a_i-b_j)\)(就是两个对 \(r\) 的要求 \(i\) 放前更低),分讨一波可以得到 \(a_i+b_i > a_j + b_j\)。
- P5888,绿,dp。乍一看是矩阵乘法,但实际上那两个范围和矩阵乘法的要求是反的。\(n\) 非常的大,但受到限制的只有后面涉及的 \(10^5\) 个,所以没受限制的可以一起求,后面的跑 dp 就行了。
- P6015,绿,双指针。对于一个确定的第一次选到的位置,肯定是要让 \(X\) 把后面能取到的把前面更大的卡掉。然后更大的与前面的值之间就是存在必胜方案的 \(X\)。卡掉的位置用双指针,覆盖用差分。
- P6103,绿,dp。因为放啥和性质无关,只和长度有关,可以大力 dp。但因为函数不加括号就变成值,加了又是函数又可以变成值,与值加括号相重复,所以要加一类以括号结尾的值。
- P3389,蓝,模板。
- P6196,绿,思维。相邻的至少乘一次,但乘法有不同,一个被两边都乘的必须满足它是 \(1\) 才更优。所以按照 \(1\) 分成若干组。组中间的因为去除完、乘完后会剩下一个呗加一次,加最小的即可。
- P6786,绿,数论。化简式子可以得到 \(b_j = \frac{3}{2} b_i\),因为有限个,所以不可能有两组这样子一直乘上去的,所以从小到大枚举每一个尝试往上跳就可以了。所有相同的都是一样的,直接取了一个就全取上即可。
- P6852,绿,思维。这个限制就是一些地方可以放后面那个,另一些地方不可以。对于 \(i\),\(v > i\) 的限制的交去掉 \(v=i\) 的限制就是它能放的。因为得有交才可能不无解,所以有解时除了 \(0\) 的限制肯定都是有交的,即排除的也是整段的,这些可以直接尝试取可能取的左端点和不能取的右端点的后一个。对于 \(0\) 的限制特殊处理。
- P7044,蓝,数学。容易得出一个形如 \(\sum_l{\choose}\sum_r{\choose}f(l, r)\) 的式子,\(f(l, r)\) 是 \(l \rightarrow r\) 不匹配的括号数目。那么枚举一个左端点,发现把左端点去掉后后面除了和当前匹配的后面都会增加一步,其它都会少一步。那么对后一个组合数后缀和,并处理处匹配即可。
- P7320,蓝,图论。无向图的 dfs 树没有横叉边,所以若叶子数足够独立集数,直接输出叶子就可以了。否则按 dfs 序排列叶子,在最后补上根。然后前一半和后一半一个个配对,这样一个点下面的要么和根连上了,要么和另一半连上了,肯定会覆盖这个点。即所有点都可以被覆盖。不够的链一个个点补就可以了。
- P7291,绿,单调栈。如果一个后面的数比前面的数要大,那么前面那个数被算进答案里只有取其后第一个比它大的时候,不然把大的那个算进去对于后面的每一个肯定不会更劣。若取一个比其前的,同样也是要第一个比其大的。单调栈即可。
Day -127
- P6583,蓝,数论分块。要求的分数必须是 \(\frac{ac}{bc}\) 的形式,\(c\) 是不含 \(2, 5\) 因子的数,\(b\) 是只含 \(2, 5\) 因子的数,\(a\) 是任何数。那么枚举一个 \(c\) 的值,问题就变成了 \(f\left(\lfloor\frac{n}{c}\rfloor\right)\lfloor\frac{n}{c}\rfloor\),\(f\) 是范围内只含 \(2, 5\) 因子的数个数。可以用数论分块解决,注意 \(c\) 是不含 \(2, 5\) 因子的数,所以数论分块时乘一段得容斥去掉含 \(2, 5\) 因子的。
- P5889,蓝,线段树。主要的问题在于碰到根节点怎么办。可以在线段树上再维护一个值,即碰到根之后会到达的点。并且维护整个过程中会向上跳的最大距离。若右边上到最高,那么碰根到的就是右边到的,否则是左边碰根到的再跳上右边的。
- P7444,蓝,dp。先可以写出一个三维的状态来。然后发现对于每次的一个 \(l\) 只有一个 \(r\),因为 \(a\) 的一段后缀和是可以用 \(l, r\) 来表示的,确定了一个也确定了另一个。然后转移也不需要那么多,因为要转移必须满足当前的 \(a\) 要么是左边的倍数,要么是右边的倍数。这样每次转移就是根号级别的,总时间复杂度也是线性根号的,通过滚动可以把空间压到线性。
- CF1606E,2100,dp。开始我设的状态是 \(f(i, j)\) 表示 \(i\) 个人分配 \([1, j]\) 的方案数,但这样转移要两维。这个 dp 的问题在于“分配”这个限制太宽了,得枚举下面最大的值,而且一下子去掉人的转移也太难了。把状态改为最大值是 \(j\) 并且每次可以不少人就可以转移了。
- CF1599H,2100,数学。在边界上询问曼哈顿是单峰的,但这里不能三分。因为两边都是一次函数,中间平了一段,且函数对称,所以直接找到中点询问就可以了。
- CF1202C,2100,前缀和。枚举每个操作,只对后面有影响,所以把横纵坐标分开,记前缀后缀最大最小值,和新的极差的积取 \(\min\) 即可。
- P7339,绿,分治。直接贪心能取的就取最大,不然取最小是错的。因为可能通过超出的干掉更大的,再通过没超出的干掉这个超出的。正解是对于每个区维护一个列表存能赢的,合并的时候看是否能在另一边找到一个能胜的,再归并排序即可。
- ABC230F,?,dp。赛时的题。发现如果没有 \(0\) 参与那么每次要么接入上一组要么开新的一组。对于最小的一段 \(0\) 后面的那个状态会和 \(0\) 之前的重复。所以开个
std::map
存每个前缀和对应的最后一个 \(f\),在更新时减掉就可以了。
Day -126
- P6016,蓝,矩阵乘法。发现一旦确定第零天,后面都确定了。相当于有向图走若干次哪些点能到,直接用
bitset
优化的矩阵乘法。 - AT4111,?,思维。中位数最多偏移一位。(然而我居然赛时在用
set
模拟)。 - AT4112,?,组合数学。肯定是最大的和最接近其中间的,因为如果有小的,比起还要接近中间的,直接把 \(n\) 换成更大的肯定更优。
- AT4113,?,退火。模拟赛时做不出,直接无脑退火,居然过了。由于数据小,其实搜索也能过,只是写起来复杂得多。
- P6198,蓝,思维。因为要求的是排列,所以若变小或不变会把前面都抬升。那么不确定的肯定是前一个加一。确定之后可以按 \(1\) 分割整个数组,因为栈清空了一遍一定是后面比前面小,且中间的相互独立。然后递归进去若只剩下 \(2\) 最小,那么栈底不会移动,直接不理会它,这样递归处理即可。
- P6381,蓝,图论。把数字质因数分解,能转移的一定是模 \(k\) 意义下所有因子个数都相等的,可以把这些因子哈希起来或者存进
std::vector
里作为状态。
Day -125
- P3372,黄,模板。学习并写了一遍 zkw 线段树的板子。
- P6688,蓝,线段树。两个集合的差肯定是和除以长度。那么问题就变成了要找到一种神奇的哈希,使它能快速得到全部加上一个数的哈希值。\(\text{hash}_v = g^v\) 满足条件。
这题怎么卡unsigned long long
啊,害得我调了好久。 - P2023,绿,线段树。模板题。
- P4513,蓝,线段树。线段树维护最大子段和。三年前无法理解的题现在一看就会了。 😃
- P1471,蓝,线段树。方差等于方的和减去和的方。所以维护方的和与和的方就可以了。
- P6327,蓝,线段树。用正弦余弦和角公式维护正弦值和以及余弦值和。
- P3467,绿,单调栈。维护一个严格单调递减的单调栈,如果弹出前面那个比当前大,那么每个用一个还是得用,而如果一样大,总数就可以减少一个了。
Day -124
- P7706,蓝,线段树。把那个式子拆成两个部分维护,并把维护它们需要的给维护一下就好了。
- P3792,紫,哈希。求出区间的和之后就可以知道如果它们是值域上连续的部分左右端点是什么。再使用经典随机权值异或的哈希方式判断这一段的集合和应该有的连续值域的集合有没有不同即可。但是值域太大,需要离散化,处理离散化后不连续的连续的问题可以把每个数加一后也放入离散化数组中。
- P5278,紫,线段树。
其实这题也可以哈希等差数列的限制可以通过极差、相邻差的 \(\gcd\)、是否重复出现来表示。维护这些东西即可。注意维护是否重复出现的时候给搞一个双向链表,把链表更改涉及到的全部在线段树上更新。另外注意公差是 \(0\) 的情况。 - CF1446D1,2600,思维。一个结论是,整个数组中出现最多的一定也是答案中出现最多的。因为如果它不是,那么可以把区间向两边扩展,肯定有一个时刻另一个众数和它数量相同,此时区间长度还更大。那么枚举另一个数,把它和整段的众数分别记为 \(1\) 和 \(-1\),其它记为 \(0\),然后求最大的前缀和相同的端点构成的区间就好了。
- CF1446D2,3000,根号分治。考虑根号分治
这怎么想得到是根号分治啊喂喂,对于出现次数大于根号的,按照 easy version 的方法进行处理。不然枚举它的出现次数 \(t\)(肯定不会超过根号),然后双指针使当前段所有数出现次数不超过 \(t\),并维护每个数出现次数 和 出现次数的出现次数。判断是否是好的序列并更新答案即可。 - P4139,紫,扩展欧拉定理。扩展欧拉定理:若 \(m > \varphi(a)\) 则 \(a^b \equiv a^{b \bmod \varphi(m) + \varphi(m)}\)。发现上面那个幂还是题目的形式。而且不断取欧拉函数后变为 \(1\) 的次数是 \(\log\) 级别的,所以直接递归处理。
- P3747,紫,线段树。由上面一题得到这个操作只有 \(\log\) 级别次,那么直接暴力做就行。其实不行,因为线段树上一只 \(\log\), 递归求再一只 \(\log\),快速幂再一只 \(\log\) 会 T,所以先按 \(10^4\) 分块处理好幂次,并记录是否超过 \(\varphi(m)\),求的时候拼块即可。
- P7715,绿,树状数组。考虑 H 形中间的那一个,先处理出上下最大的都能扩展的,发现要当前行每一个和它取 \(\min\) 相加。那么把大于它和小于它的拆开,则一个是和一个是个数乘上这个。那么用值域树状数组维护。
Day -123
又是调题调到吐的一天 /dk
- P4344,紫,线段树。终于明白这种题该怎么线段树上单 \(\log\) 二分了!先找到最后一段没有被完全取到的线段树上的区间,再在这段区间里二分就可以了。
- CF689D,2100,二分。左端点是固定的情况下右边端点递增时两个值都是单调的,所以二分出一个满足大于等于条件的,一个满足大于,相减就是等于的区间了。
- CF1551D2,2100,构造。显然方案是上面一排排排横的,然后每列被占用的数量都是偶数。所以尽量去占满一列,然后后面保证剩下的是偶数放。但这样有一个问题,就是 \(n\) 是奇数的时候后面让它空就完蛋了,所以这种情况先把一行盖满再执行上面的操作。
- CF1560F2,2100,思维。这题实现比我想象中的优美多了。找到第一位不满足要求的位置把它增大直到能满足条件。具体实现是每次找到一位不行的将其加一,因为从高位开始找,所以这个不行的位一定往低处走,只需要枚举 \(10 \times 10\) 次就可以出结果了。
- P4062,紫,树状数组。枚举数,对于该数出现做前缀和,绝对众数出现的区间就是前缀和减下标比当前位置小的。发现前缀和被出现的数分成了很多段,而总段数只有 \(n\),所以只要一段段更新就可以了。对值域上做前缀和,由于知道段就可以算出这一段的值域,所以再对这个前缀和作前缀和就可以了。用树状数组维护这个东西,就是做差分数组的三级前缀和。
- P7853,绿,二进制。第一问就是进位总数,无论怎么安排都是不会变的。而第二问就是要尽可能排除 \(1\) 一次进位,那么把每一个位上能出现的个数记个数,并加上前面对后面的贡献,找到最大的一段全 \(1\) 就可以了。
- P6617,紫,线段树。用线段树维护补数前驱的最大值即可。但这个怎么更新呢,毕竟一个可能有多个补前驱/后继。有一个非常 nb 的 trick,如果补前驱在前驱的前面,那么就不管它就好了,因为如果能取到前面那个也一定能取到,不能取到就是不能取到。然后一堆细致的维护即可。
Day -122
- P3369,蓝,模板。用 Treap 实现了该模板。
- CF886C,1300,思维。题意要求就是忽略掉若干个关系,然后每个数就是和以该数为下标的位置是同一组的了。但是每次连只能连该组的最后一个。如果有多组可以加入时,不管加入哪一组都没有区别(包括新建一组),所以直接开一个数组维护每组最后一个就行。就这 \(1300\) 我做了 20min /ll。
- CF886D,2000,思维。首先不可能有出现两次的字符,因为一个字符出现两次,包含它的集合中的字符串也要出现两次,这样它的出现就不止两次了,而是无限地增加。那么每一个字符必然有唯一的前驱/后继或者任意前驱/后继。把前驱后继记录一下,有多个直接输出无解,然后选择最小的可以开头的填就行。
- CF886E,2400,dp。枚举第一个不合法的位置,如果知道了前面没有返回时的方案数 \(f_i\) 就可以把答案用 \(\sum f_{i-1}{n-1 \choose n-i}(n-i)!\) 来表示了。所以考虑 \(f\) 怎么求。在这题中,数的绝对大小不重要,重要的是相对大小,所以任意 \(i\) 个数组成的 \(f_i\) 都是相同的。枚举当前最大的值出现的位置可以得到 \(f_i = \sum_{j=i-k}^{i}f_j {i-1 \choose i-j}(i-j)!\) 把组合数拆开 \(f_i = (i-1)!\sum_{j=i-k-1}^{-1}\frac{f_{j-1}}{(j-1)!}\),后面的和式可以用一个变量来添尾去头地维护,这样就在线性时间内解决了这个问题。这种问题似乎都是先发现一个二维的式子然后一通转化使它能被维护。
- P6136,蓝,模板。用 fhq-Treap 实现。
- P3391,紫,模板。用带上懒惰标记的 fhq-Treap 实现。
- P5482,蓝,树状数组。按将输入分成必胜/必败/大于/小于四组,大于小于用权值树状数组维护。
- P2596,紫,平衡树。平衡树上节点不仅维护一个权值,还维护一个编号,并维护编号到平衡树节点的转换即可。
- P7840,绿,贪心。首先每个点度数 \(1\) 是必须的,然后发现剩下的度数无论怎么分配都可以构造出方案,那就用优先队列取最小就可以了。
Day -121
- CF817E,2000,trie。trie 树上维护每个节点为根的子树中有多少个,查询的时候往和要求相同的方向走,若当前位置为 \(1\) 则把另一边加上。
- CF56E,2100,dp。\(f_i\) 表示第 \(i\) 个位置能压倒几个。从后面开始转移,每次判能不能压倒下一个、能不能压倒下一个不能压倒的第一个、能不能压倒下一个不能压倒的第一个不能压倒的第一个……这样子每个最多只会被判一次,所以复杂度是对的。
- CF1056E,2100,哈希。枚举第一串的长度,如果不能让另一个整除直接去掉,否则跑一遍来判断。时间复杂度是 \(\frac{|s||t|\gcd(cnt0, cnt1)}{cnt0^2}\) 因为由 exgcd 知识可知那个式子的两个解相差 \(\frac{cnt_0}{\gcd}\),上面最大是 \(O(|s||t|^2)\),而我们让 \(cnt0\) 变成出现次数多的那个,直接就把 \(|t|^2\) 消掉了,所以复杂度是对的。
- CF1201D,2100,dp。每次肯定停在最左边和最右边,因为从左边右边出发到下一行不会劣与先到了所有宝藏的位置再瞎跑到某个点。按照这个 dp 即可。
- P3835,紫,模板。每次分裂合并的时候新开节点即可。
- P7807,绿,树。我做复杂了,官方题解做法是发现若 \(x\ne 0\),要使有解,解必然是树的直径长度减去 \(2\)。
- P2042,紫,平衡树。平衡树上再维护一些节点记下当前子树的信息,注意合并的时候得把当前节点加上,这点和线段树不同。
- P4036,紫,平衡树。线段树可以维护哈希值,平衡树也可以。
- P3215,紫,平衡树。这题需要注意平衡树上进行各项操作的优先级。优先级其实就是将区间表现成新进行某个操作再进行另外一个操作。这题中得先进行取反操作,再覆盖,最后翻转,取反的时候要把覆盖标记也取反。
Day -120
- CF1195E,2100,单调队列。直接横纵都做一遍单调队列。
- CF1187E,2100,dp。\(f(i, 0/1)\) 表示 \(i\) 点向上/向下的最优答案。注意贡献计算的时候不要计算重复或遗漏了,在这题中要注意向上的初始贡献不是 \(0\) 而是向上的子树大小。
- CF1185G1,2100,dp。直接状压。
- CF1185F,2100,dp。把使用原料的状况压成一个二进制,然后 dp 记下到每个状态的最优答案,然后枚举状态看覆盖了几个人并更新答案。
- CF1184E2,2100,树。建棵最小生成树然后每条非树边看所在环的最大值即可。
- CF1184E3,2400,树。非树边和 E2 是一样的,对于树边,必须得是所有涉及它的环上的最小值。可以在树边时更新端点见路劲上边的答案。不需要树剖,直接从小到大去覆盖,用并查集维护没有覆盖到的即可。
- P5069,紫,树状数组。因为一个被减旁边也被减,所所以将序列划分成若干段上升或下降的区间只有和最大极值奇偶性相同的才会有贡献,把它们都加上即可。可以从极小点来计算答案。极值点用
std::set
来维护。
Day -119
\(\color{orange}\text{Error.}\)
Day -118
\(\color{orange}\text{Error.}\)
Day -117
复习了之前写过的一些技巧的板子题。只记录一下之前遗漏的一些问题。
- 写树上背包的时候要写成“我为人人”的 dp,这样才能保证每次转移都是合法的,即每一对点都被合并了一次。否则复杂度错误。
- 一些二维偏序的带插入删除的可以加一维时间然后用三维偏序去做,每次计算一个时间点新增的贡献,最后前缀和得到答案。
- 扫描线使用的线段树与普通的线段树不同,因为其标记没有下传,只是一个区间如果被覆盖超过 \(0\) 次就把这个变成区间长度,否则是左右儿子被覆盖的长度的和。所以正好包含的那个区间里面也要做 pushup,同时空间可能要 \(8\) 倍。
- 扫描线一条线化成两条,空间要开两倍。
Day -116
- P3527,紫,模板。整体二分的模板题。整体二分适用与一些每个位置都要二分的问题(?)。大致思路是确认一个
mid
在哪些询问中合法就扔到左边,不合法扔到右边,然后对新的两组询问和新的取值范围继续进行二分。 - P1527,紫,整体二分。注意: 整体二分的复杂度必须要是每一步处理复杂度数据规模都是在区间范围内才是正确的,比如这题不能每次跑 \(n^2\) 然后再判断,因为那样复杂度就变成了 \(q \log q \cdot n^2\) 了。
- P1429,蓝,模板。平面最近点对。
- CF600E,模板。 dsu on tree 的模板题。dsu on tree:每次暴力统计子树中的答案,把重儿子放在最后,统计的答案不清空。因为每个点只会被到根路径上的轻边计算一次,所以复杂度是 \(n \log n\)。
- CF1167E,2100,思维。若一个区间可以,扩大以后也一定可以,所以枚举一个 \(l\) 找到最小的合法的 \(r\) 就可以了。这个 \(r\) 必须满足的性质是 \(r\) 到最大的那一段合法,即后面的第一次出现最小的不能比前面的最后一次出现的早,这个 \(r\) 的范围可以预处理出来,然后对于 \(l\) 也进行差不都的操作并保证 \(r\) 后面的没有出现在 \(l\) 前面的之前就可以了。
- CF1166E,2100,构造。如果一个区间和另外一个区间没有交那肯定是不合法的,因为 \(\text{lcm}\) 是不会让一个数变小的。如果区间两两都有交,那么可以给每个区间都分配一个质数,然后把区间内的都乘上那个质数,这样每个区间的最小公倍数得是所有分配的质数的积,而它的补集没有分配给它的质数,肯定更小。
- P1856,蓝,模板。扫描线求周长并的模板。求周长并和求面积并略有不同,得把横纵分开计算,横的是两个扫描线之间的差,纵是扫描线交到的段数的两倍乘上扫过的距离。
- P3812,蓝,模板。线性基。
线性基是向量空间的一组基线性基是处理异或问题的很好的数据结构。每次插入的时候从高位到低位,如果这一位上已经存了值了就把要插入的值异或上该值,直到没有的地方就插入进去。这样子保证了原数组异或可以得到的线性基数组异或也可以得到,且线性基异或得到的不会重复,线性基数组每一个位上存的都是以其为最高位的二进制数。 - CF1100F,线性基。这应该算是前缀线性基的模板。在维护线性基的同时维护每个位置上插入的数的下标,后进来的如果遇到有的位置就和它互换后继续插入,这样子就相当于从当前位置向前反向建立了一个线性基,查询的时候只要不理会插入时间早于要求的位置的即可。
- P5787,紫,模板。线段树分治的模板题。线段树分治就是对时间建一个线段树,把每一个东西缩存在的时间都放到线段树的相应位置,然后遍历整棵树,在一个节点加入所有影响,在出节点的时候撤销所有影响,在叶子的时候更新答案即可。
- CF1163D,2100,dp。\(f(i, j, k)\) 表示到第 \(i\) 位一个匹配了 \(j\) 位一个匹配了 \(k\) 为的最大答案。处理出失配后最大能配上的位置,不断跳 kmp 的 next 数组直到下一位是要求的即可,这个可以预处理出来存在数组里。注意 kmp 的 next 数组意义是已经匹配上了几位失配后会匹配上几位。
Day -115
- CF1009F,长链剖分。长链剖分优化 dp 的板子。长链剖分就是把重儿子改成儿子中子树深度最大的,并改名叫长儿子。每次同 dsu on tree 一样先转移并继承长儿子的答案,长儿子的答案 \(O(1)\) 继承,其它的暴力合并,这样暴力合并只会在长链端点暴力合并一次,总时间复杂度是 \(O(n)\) 的。但长链剖分优化的局限性是显而易见的,必须得让长儿子能 \(O(1)\) 转移才行。
- CF587A,1500,二进制。每次做一个其它扔高位即可。
- CF587B,2100,dp。\(f(i, j)\) 表示 \(i\) 个点匹配到 \(j\) 的方案数,每次只能从 \(i-1\) 的 \(a_k < a_j\) 的地方转移过来,这个限制用树状数组或排序后记录前缀和即可。注意 \(l\) 非常大!它参与运算的时候也要取模!
我为此吃了两发罚时了。 - CF587C,2000,倍增。\(a\) 只有 \(10\),所以倍增 lca 的时候暴力合并就可以了。
手速唯一比 dd_d 快的一次 - CF587E,2900,线性基;线段树。昨天刚学过线性基还是没有做出来。因为线性基是 离线数据结构,所以是没有办法区间修改的。我们将原数组差分以后建立线性基,再把区间开头的数插入这个线性基里面,这样和原数组建立的线性基是等价的,因为每一个原数组的数都可以用这个线性基里的东西表示。那么问题转化为单点修改区间查询,就可以用线段树维护线性基了。再来个树状数组区间修改单点查询起始点即可。
- CF601E,线段树分治。进入的时候 dp 往后推若干位,出的时候再忽略这些位即可。
Day -114
- P3648,斜率优化。容易得到暴力的 dp 式子,发现这个东西是标准的斜率优化,但是写斜率优化和推式子有点麻烦,所以使用分治来转移。\(solve(l, r, L, R)\) 表示 \([l, r]\) 中的转移区间在 \([L, R]\)。求解一个中点的最优转移然后分治过去就可以了。
- CF868F,斜率优化。同样用分治来转移。
- P4178,点分治。点分治的模板题,每次找到一个重心然后算经过这个点的答案。统计经过一个点的长度不超过 \(k\) 的边数可以在这个子树里面求出深度,然后转换成一个数列,找俩和不超过 \(k\) 的,这个东西可以双指针。
- P3806,点分治。
- CF1154F,dp。反正买啥都可以,那么直接排个序求最小的 \(k\) 个,然后从后往前做个 dp 看最大可以免费哪些。
- CF1158C,构造。考虑没有 -1 的情况,可以递归处理,对于一个区间先分配给右边连到 \(r+1\) 的,然后递归处理下去。而如果有 \(i < j < next_i < next_j\) 的肯定无解。所以构造不存在问题。
- CF1152D,卡特兰数。别想着麻烦的 dp 了。题目本质是要求那个卡特兰数数组在 \(i+j\) 是偶数的时候的情况,因为深度是奇数的点每个都只能下面连一条边。
- CF1151E,思维。考虑每条边和每个点产生了多少次贡献即可。
- P6329,点分树。模板。点分树就是根据重心重构整棵树,注意点分树上的距离和原式距离大小上没有联系了。
Day -113
- P4151,线性基。对每个环的答案都扔进线性基里面,这样因为异或的优美性质,所有的路径都可以相互转换,只要随便选一条 \(1 \to n\) 的路径然后再线性基中求最大值即可。
- CF938G,线段树分治。这题就把上面一道题套一个线段树分治,并且用带权并查集维护两点之间的异或。注意带权并查集!
- CF526F,扫描线。维护区间 \(\max - \min = \text{len} - 1\) 的。把 len 移到左边,式子最小值就是 -1 所以扫描线并用线段树维护区间这个最小值的个数即可。需要用到单调栈来维护 \(\max\) 和 \(\min\) 影响的位置。
- CF997E,扫描线。上面一题的加强版。不止要以右边端点为端点了,所以再线段树上打一个 tag 表示这段的答案记录几次,仔细想一想这样是对的,因为两个标记一起往下传在一起的标记还是会在一起,更新 tag 的时候要先把修改给改上去再统计这个。
- P2619,wqs 二分。
- P1484,wqs 二分。可以证明这个答案的最大值关于 \(k\) 上凸,所以二分一个斜率找到答案最大的 \(k\) 小于等于限制的位置。存疑
- CF1499F,dp。树上 dp。
- CF739E,wqs 二分。wqs 二分去掉一个限制之后再在里面套一个。
- CF797E,根号分治。下面那个操作再 \(k > \sqrt n\) 的时候不会做超过 \(\sqrt n\) 次,而如果 \(k < \sqrt n\) 直接预处理出来就可以了。
Day -112
- CF1146D,数学。模拟后可以发现在跳过 \(a, b\) 中大的那个完整的两倍之后能跳到的就是最大公约数间隔的了,所以可以直接 \(O(1)\) 计算出来,之前的暴力就行。
- CF1120C,字符串。暴力 dp 多了一只 \(\log\) 是过不了的,所以考虑优化。显然这个 \(f\) 是单调递增的,那么就是要让转移的尽可能远,枚举前面的一个位置 \(j\),\(j\) 之前的只从 \(j\) 之前和 \(i\) 之前最长公共后缀处转移即可。
- CF1117D,矩阵优化。枚举最后一个放魔法石还是普通石可以得到一个简单的递推,因为 \(m\) 只有 \(100\) 所以直接构造矩阵转移。
- CF1108F,最小生成树。对于每条非树边必须得加到所在的树的环中最大的更大。
- CF1108E2,线段树。枚举每个作为最大值的点,把不包含其的线段全部取上。可以通过把线段挂在端点,然后用线段树来维护。
Day -111
早上打省选计划模拟赛也没做出什么结果 /kk
然后 sb 题又调了很久。
所以没有啥好写的了。
Day -110
- P6835,概率期望。关键在于期望具有线性,即 \(E_{x \to y} = \sum_{i=x}^{y-1}E_{i\to i+1}\)。然后就把问题转换成了求 \(E_{x \to x+1}\)。
- CF1614D1,dp。前缀 \(\gcd\) 肯定是不断递减的,设 \(f_i\) 表示含 \(i\) 因子的数排成一排的最大答案,\(f_i\) 可以由 \(f_{i \times prime}\) 得到,只需加上后面的是 \(i\) 的倍数但不是 \(i \times prime\) 的倍数的数的个数乘上 \(i\) 即可(这一段前缀 \(\gcd\) 是 \(i\))
- CF1098B,模拟。隔行或隔列互不影响且字符集相同,那么枚举第一行的字符集即可,列同理。
- CF1070E,二分。感性理解可以想到答案关于 \(k\) 是单峰的,因为前面会被任务数限制,后面会被时间限制。但是这里因为可能有一段是平的,无法进行三分。但我们知道峰一定是在两种限制交界处,所以二分找到交界处就可以了。
- CF1066F,dp。那个限制等价于一个个正方形,必须先到里面的正方形上的点再到外面正方形上的点。显然最后得停在每个正方形上点的左/右端点上,dp 即可。
- CF1039B,二分。二分确定一个大概的区间,同时在每次扩大 \(l, r\) 保证火车不跑出我们的区间,然后在区间里随机询问即可。
- CF1044C,几何。若 \(i > 4\),肯定是 \(f(i) = f(4)\),因为保证输入是凸包且距离是曼哈顿距离,只要选出每个维度上最极限的点就可以了。然后考虑 \(f(3)\),因为三个点最后的答案却又四条边,所以一定有一个点再俩边的交点上。这个肯定得贴到原来的大正方形的两边,再把对面的那个点贴上,所以这俩点一定是极限点。最后只有一个点需要枚举,枚举即可。
- 四个板子:乘法逆元、exgcd、卢卡斯、BSGS。
- 晚上做题效率还得加强。
Day -109
- P6091,模板。原根的板子,虽然不会证,但还是记下结论吧:原根判定定理 \(g\) 是 \(m\) 的原根当且仅当对于任意 \(m\) 的质因数 \(p\),有 \(g^{\frac{\varphi(m)}{p}} \equiv 1 \pmod m\)。最小的原根数量级是 \(n ^ {0.4}\)。只有 \(2, 4, 2p^x, p^x\) 有原根。求出最小的原根后其他的原根都是 \(g^k\) 且 \(\gcd(k, \varphi(m)) = 1\)。
- P2303,数论。注意一个数的因数个数是 \(\sqrt[3]n\) 级别的!!!
- CF1334E,数论。一个结论是若 \(a | b\),那么 \(b \to a\) 一路往下走一定是最短的。那么就走到 \(\gcd\) 中转即可。
- CF1607H,双指针。首先肯定是按照 \(a_i+b_i-c_i\) 分成若干组,因为不同组肯定不能相同。然后本来想的是分成若干个上升序列,但是这样的限制太弱了,要对 \(a_i\) 和 \(b_i\) 同时限制。但是如果我们把 \(a_i'\) 的范围精确求出来,这样满足 \(a_i\) 的限制也满足 \(b_i\) 的限制了。这样就把问题转化成了若干个线段求最少的点覆盖,贪心即可。
- P4774,数论。对于形如 \(k_ix \equiv a_i \pmod{b_i}\) 的式子直接用类似 excrt 的思想合并并把模数变成 \(\operatorname{lcm}\) 是错误的,因为它们俩的通解不是让 \(x\) 一直加模数的最小公倍数。对于 \(kx \equiv a \pmod{b}\),通解其实是 \(x = x_0 + pt\),其中 \(t\) 是最小的满足 \(kt \equiv 0 \pmod b\) 的,即 \(\frac{b}{\gcd(k, b)}\)。求出一个特解之后合并形如 \(x \equiv x_0 \pmod{\frac{b}{\gcd(k, b)}}\) 的同余方程组才是正确的。注意:在生成同余方程的时候 \(x_0\) 也要使用龟速乘并相应的取模!
因为这个调了一个晚上。
Day -108
学习炫酷反演魔术(莫反)!
学习炫酷多项式魔术(FFT)!
Day -107
炫酷反演魔术!(继续莫反 /kk)!
- P3312,莫反。记录一下这道有点难的莫反推导。
题目要我们求的是
\[\sum_{i=1}^n \sum_{j=1}^m[\sigma_1(\gcd(i,j)) \le a] \sigma_1(\gcd(i,j)) \]先换个元后面推导起来方便。
\[\mathbf{f}(x) = [\sigma_1(x) \le a] \sigma_1(x) \]原式变成
\[\sum_{i=1}^n \sum_{j=1}^m \mathbf{f}(\gcd(i, j)) \]将 \(\gcd\) 拉到开头来枚举。答案变成
\[\sum_{d=1}^n \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\mathbf f(d)[\gcd(i, j)=1] \]把 \(\mathbf f(d)\) 提到前面,处理 \(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\epsilon(\gcd(i, j)=1)\),经典 \(\epsilon = \mathbf 1 * \mu\),所以原式变成了
\[\sum_{x=1}^n \mathbf f(x) \sum_{i=1}^{\lfloor\frac{n}{x}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{x}\rfloor} \sum_{d|i, d|j} \mu(d) \]再把 \(d\) 提到前面去枚举,式子变成
\[\sum_{x=1}^n \mathbf f(x) \sum_{d=1}^{\lfloor\frac{n}{x}\rfloor} \mu(d) \lfloor\frac{n}{xd}\rfloor \lfloor\frac{m}{xd}\rfloor \]然后这个式子还是不够美观,我们把 \(xd\) 提出来枚举,设为 \(k\),这样枚举 \(x\) 就变成了枚举 \(k\) 的因数,枚举 \(d\) 就成了 \(\frac{k}{x}\)。于是原式变成
\[\sum_{k=1}^n \lfloor\frac{n}{k}\rfloor \lfloor\frac{m}{k}\rfloor \sum_{x | k}\mathbf f(x) \mu(\frac{k}{x}) \]然后再把 \(\mathbf f\) 展开
\[\sum_{k=1}^n \lfloor\frac{n}{k}\rfloor \lfloor\frac{m}{k}\rfloor \left(\sum_{x | k}\mathbf [\sigma_1(x) \le a] \sigma_1(x) \mu(\frac{k}{x})\right) \]把 \(a\) 排序,用树状数组维护后面括号里的前缀和,用数论分块计算答案就可以了。
炫酷多项式魔术!(NTT)
不用 long long
一定要时刻注意取模!确保乘法一定被强制转换且一次乘法取一次模!
Day -106
- P5330,数论。注意到对于 \(A\) 中的数,每次加 \(p\) 模 \(q\) 的值是循环的,且循环长度为 \(\frac{q}{\gcd(p, q)}\)。而且,所有循环是不相交的,这意味着你处理出所有循环复杂度是 \(O(n)\) 的,那么就处理出前缀和后计算 \(A\) 中每个数的答案就可以了。
- P5323,概率。推式子!
- P7992,容斥。首先进行一步容斥,就是答案等于满足左边不等式的加满足右边不等式的减去 \(n^2\),相当于满足两个限制的等于分别满足两个限制的和减掉总量。然后考虑对于每个 \(k\) 满足 \(a_i+a_j = k\) 的有多少(另一个限制同理),先统计出 \(a_i = k\) 的有多少,然后枚举 \(i, j\) 并把 \(c_i \times c_j\) 加进 \(c_{i+j}\) 即可。这个过程相当于一个多项式乘法,可以用 FFT 优化至 \(n \log n\)。
- P2606,组合。这题需要注意的是 \(n\) 可能是 \(p\) 的倍数,但是你处理出 \([1, p]\) 之间的阶乘和逆元又存不下,实际上,只要处理到 \([1, \min(n, p-1)]\) 即可。
Day -105
状态好差。
- ABC233,又没过 F /dk。感觉比赛的时候太着急要过了,一些很基本的地方都没有想清楚。 https://www.cnblogs.com/Acfboy/p/ABC233F.html
Day -104
ERR.
Day -103
- 省选计划模拟赛补题。这次的 A 和 C 还是非常可做的。A 考虑正难则反,统计每个颜色没有出现的,然后对 \(k\) 维护答案,每次修改相当于在区间加入了一个等差数列,这个可以用树状数组解决。
- C 考虑克鲁斯卡尔正常的做法,只需要找一个数据结构代替并查集判断是否在同一个和并完成合并即可。可以直接标记颜色并启发式合并,每次加边的时候判断颜色串哈希值,如有不同,不断二分出最早的合并。
- 复习了一下 tarjan。
low[u] = min(low[u], dfn[v])
的原因:low
除了原来的作用还起到了区分子树的作用。 - P4314,线段树。维护历史最值还得维护区间历史最大标记。
- GSS2,线段树。离线下来后倒着扫,加入点只加会影响到的位置,然后查询区间历史最值就是答案了。
Day -102
- CF1580C,根号分治。对于 \(x_i + y_i > B\) 的,总共引起的变化不超过 \(B\) 次,直接修改差分数组就可以了。对于其它情况,循环周期不超过 \(B\) 个,可以对于每个周期进行差分。注意加入和修改的标记在当前之前时要加入当前答案。
- P7368,二分图最小点覆盖。最小点覆盖数等于最大匹配数。
- CF1579G,二分。二分牛啊!区间越大越容易满足,有单调性。考虑怎么进行验证。\(f_{i, j}\) 表示前 \(i\) 个的终点能否落到 \(j\),这个可以直接用 bitset 来转移。最大答案不超过最大的长度的两倍,在这个范围内二分即可。
- CF1340F,线段树。这题真的是从早调到晚啊。大概思路是把区间内能消掉的都消掉,然后记录左边的右括号和右边的左括号的哈希值,进行比较。但是这样实现起来有一些问题,如果按照传统的合并区间的方式来做就没有办法获取一段区间内最后/最前的若干个左/右括号数的哈希值了。考虑这个东西应该要怎么维护。如果进入的区间都是线段树上刚刚好的一个点,那么可以直接用线段树二分做,但这样一来没法处理询问时的合并了,因为没法快速确定上一个段。那么先把线段树上每一段都拉下来组成序列再做。
- CF1567E,线段树。用类似最大子段和的方式处理跨区间答案就可以了。
Day -101
早上瞎做集训队胡策题(找朋友,调整算法),得出结论:退火什么用的没有!
- 2-SAT。两个限制相当于一个不满足一定要满足另一个,所以对每个命题建两个点,一个是满足的,一个是不满足的,按照输入连边。进行缩点和拓扑,若一个点和它不成立的那个点在同一个强联通分量肯定不行。不然如果它排在不成立的那个点后面就是真,因为它不成立的那个点补成立它就成立。
- P6577,KM。useless algorithms 毁我青春!
Day -100
百日倒计时了。
- 炫酷网络流魔术!
Day -99
模拟赛报灵了 /kk
- 模拟退火屁用没有!调整法 yyds!模拟赛 t1 调整法直接就冲到 70 了,下次不止考虑退火了,对于这种一个初始条件进行一些操作使最优的问题得考虑考虑调整。
- 牛客跨年赛。好吧这比赛不完全正经。我居然想很久不会确有一堆人过的题没想到 OEIS /fn 那题退火完全没有用,因为解和解之间几乎没有关联。
- 牛客跨年赛 - 最大值求和。这转化后在单调栈内二分我还真没有想到。
Day -98
碌碌无为的一天。
Day -97
这次省选模拟赛前俩题似乎太简单了。
新的一年开始了,头两天似乎还在无休止地重复过去,希望接下来能成为自己想要的样子。
Day -96
- P7771,欧拉路径。先通过是否入度和出度都相等来判定是否有解以及找出可能的出发点,然后搜索的时候标记上次到这里来是哪条边,直接从那条边继续进行。
- P3511,最大流。先进行二分,变成了判定混合图欧拉回路。那么就是要调整使得每个点入度和出度相等。建图时把流出当做增加出度。那么把出度比入度多的向汇点连边,否则从源点连边,并把原来无向图随便定的边反向连边。
- P3227,最小割。首先把每个点都建出一条长度 \(k+1\) 的链,权值是高度到当前位置的代价。这样它的最小割就代表了每个位置高度到哪里。现在考虑加入相邻相差不超过 \(d\) 的限制。只需要在 \((i, j, h)\) 与相邻的 \((x, y, h-d)\) 连边就可以了。这样你如果割在更低的位置就没法保证不连通了。
- CF103E,最大权闭合子图。这题真的是怎么想得到啊。先取反权值让问题变成最大值。把集合和其中的元素都当成节点,让集合向元素连边。集合权值为原值减去某个很大的数,元素权值就是那个很大的数,这样一来最大权闭合子图如果权值是正的那么就满足了那个限制。
- P3980,最大流。先建一条链,流量为一个大数,然后给相应的边减掉每天需要的,那么就要有其它方案来流这些流量使最后的流量不变,这就代表了一种调人方案。
- P1251,最大流。做这题的时候还发现了课件的问题 /cy。每个点拆成两个点,一个代表直接买入,所以从源点向其连流量无穷,代价为 \(p\) 的边,但连向汇点的只有 \(r_i\),然后另外一层图代表传递,相邻间连流量无限无分费用的边,和另一层之间连相应位置相应费用的边即可。这种做法的核心就在于它保证了流量最大不变的同时加入了一些无费用和费用不同的边代表一条毛巾多次使用。
- CF1593G,思维。开始我觉得小括号必须要连续的偶数段,这其实是错误的。实际上任何奇偶位置不同的相邻都可以配成合法括号,因为中间相距偶数个是一定可以合法的。那么只要前缀和记下不匹配数即可。
Day -95
- CF1615D,2-sat。对于一条边,答案只和其权值 popcount 的奇偶性有关,那么问题就转化成若干个限制,两个 0/1 点是否相同(即一条边的两个点),并且限制了一个点一定是什么(1 号点一定是 0)。只需要在传统 2-sat 的基础上加一个 \((1, 1) \to (1, 0)\) 的边即可。
- CF1562D1,思维。先不要着急把问题转化成一个数列的形式,这样容易损失性质。可以发现,相邻两个相同的对于答案没有任何影响,这样我们就把原来的那个序列转化成了形如 101010 的形式。如果长度为奇数,显然只要去掉中间那个就行了,而如果长度是偶数,原来成立最好,原来不成立去掉一个就转化成奇数的形式了,这样就做完了 D1。
- D2。把原来的答案的前缀和记为 \(s\),那么所谓中间那个点 \(k\) 就必须满足 \(s_{k-1} - s_{l-1} = s_r - s_k\),移项得 \(s_k + s_{k-1} = s_{l-1} + s_r\),把所有 \(s_k + s_{k-1}\) 相同的位置存在一起然后 lower_bound 即可。
- CF1556E,思维。先把 \(b_i\) 变为 \(b_i - a_i\),然后把 \(b_i\) 拆成一堆 \(1\) 和 \(-1\),然后可以发现如果是 \(1,1,-1,-1\) 这样的形式肯定是前面一堆 \(1\) 的和,即最大前缀和。如果是 \(1, -1, 1, -1\) 的形式肯定只有那些增大的前缀产生贡献,答案是最大前缀和,而如果最外面有一对 \(1, -1\) 那么答案肯定要比中间的答案加上 \(1\), 即最大前缀和多了 \(1\),答案还是最大前缀和,因此通过归纳证明了答案就是最大前缀和。
- P5901,根号分治。对于每一个询问,如果 \(r_2 \ge \sqrt n\),这样的 \(r_2\) 总个数不超过根号级别,那么直接对于每个这样的 \(r_2\) 遍历整棵树统计它们即可。而如果 \(r_2 < \sqrt n\) 那这样的一个 \(r_2\) 出现次数不超过 \(\sqrt n\) 个,对于每个询问跑所有的 \(r_2\) 是可以的,直接做不方便,应离线下来 dfs,维护根到当前位置的路径上的每种颜色的点个数,然后在每个点回答询问。对于第一种方案,注意直接记录每种 \(r_2\) 在子树中的颜色空间是 \(n \sqrt n\) 的,会 mle,所以需要每次统计一种颜色。
- P4016,费用流。源点往每个点连流量为改点原来负载,费用为 \(0\) 的边,每个点同时往汇点连流量为该点应有负载的边,然后相邻间连流量无限,费用为 \(1\) 的边即可。
- P2774,最小割。先全选上考虑不选哪个点。黑白染色后源点往黑点连,白点往汇点连,黑点往旁边连流量无限的边即可。这样可以保证一个点不割掉(即选上)周围必须全不选。注意只从黑点往旁边连就保证了这样一条限制,而如果白点也往旁边连那么所有点都联通了,多余的流量可以流来流去,就不对了。
Day -94
一周年了。
- CF1552F,dp。一个门被再次经过之后肯定是开着的,不然的话又给它转回去了。令 \(f_i\) 表示 \(i\) 号门要多久才能回到这点,那么答案就是 \(x_n + 1 + \sum f\)。而 \(f_i = x - y + \sum f_j\) 即跑回去后再经过中间所有门。
- CF1543D2,构造。妙妙题啊,根本想不到。首先 k 进制下的异或把二进制下的自反性给破坏掉了,所以定义一个新的运算异或减 \(\ominus\),容易得到一些结论。然后神奇的发现 \(i\) 是奇数时取 \(i \ominus (i-1)\),偶数时取 \((i-1) \ominus i\) 就可以了,这样 \(x\) 就在 \(x \ominus(i-1)\) 和 \((i-1) \ominus x\) 之间循环,总会碰上的。
- P2764,最大流。每个点拆成俩点 \(x_i\) 和 \(y_i\),一个从源点连边,一个向汇点连边,流量为 \(1\),代表最多和 \(1\) 个合并。然后按照原图 \(u \to v\) 建立 \(x_u \to y_u\) 的边,代表两点合并。跑最大流即可。
- P4688,莫队。莫队维护 bitset,处理多个相同的时候只需离散化时不去重,然后插入第 \(c\) 个 \(i\) 时把 \(i + c\) 改成 \(1\) 即可。
- P5268,莫队。把询问差分拆开后莫队。
Day -93
- P4689,莫队。同前一题拆询问,但直接做会产生 \(16\) 个询问,可能会被卡常。可以预处理出所有 \(pre_i = f_{[1, i][1, n]}\) 后进行容斥,就只有 \(4\) 个询问了。根在询问子树时需要找根所在子树,这里不需要树剖啥的,只要用 map 存下每个子树结束时的 dfs 序然后 lower_bound 即可。注意询问根的情况。
- P3939,二分。数据结构学傻了,带修莫队是过不了 3e5 的。因为修改只是相邻的,所以用 vector 存下所有位置可以直接 \(O(1)\) 修改,查询时直接 lower_bound。
- CF1535E,倍增。肯定优先取上面的。加入节点的时候维护倍增,然后每次取最上面的点即可,询问只有 \(n\) 个,如果每次不清空一个点的话最多跳 \(n\) 次,如果清空的话 \(n\) 次后就被清空完了,还是最多跳 \(n\) 次,总次数是 \(O(n)\) 的。
- P4168,分块。注意若干细节即可。
- P3674,莫队。莫队维护 bitset。加法考虑维护一个 \(N - i\) 的 bitset, \(x + y = z \Rightarrow N - (N - x) + y = z \Rightarrow (N-x) - y= N - z\) 这样就转化成减法了。
Day -92
- P5355,根号分治。对于除法,如果除数大于 \(\sqrt V\) 直接枚举较小数。否则离线下来扫的时候维护对于每个点最近一次出现商为要求的位置,每次最多修改 \(\sqrt V\) 个。
- P4097,李超线段树。注意浮点数操作。
- 卡常 P5397 /fn
Day -91
-
CF1526D。相同的字母一定是要放在一起的,因为用在原来字符串中的下标表示的话,相同的字母一定是递增的,那么另一个字母放到中间肯定没有放到旁边优,因为会错过一些。那么枚举四种字母的排列即可。
-
P5903,长链剖分。倍增处理出 \(2^k\) 级祖先并进行长链剖分,链顶记下向上和向下链长长度的若干个,回答询问的时候先跳 \(\operatorname {highbit}\) 级祖先,然后跳到链顶,这时剩下的肯定在 土链长 之内,直接用预处理的答案就可以了。因为所有链长和是 \(n\) 所以复杂度正确。
-
CF1520G。如果要用多次传送不如一次到终点,所以头尾各 bfs 一遍就可以了。这道 2200 咋是不是有点水啊 /yun
-
ABC 234
- F 看错题了浪费了一点时间 /kk
- G 第一次在赛场上想出了 G 的做法!
但是做复杂了,可惜最后 5min 之内才写完,没时间调试了。
首先可以得到一个 \(O(n^2)\) 的 dp 式子 \(f_i = \sum f_{j} \times \operatorname H(j+1..i)\),\(\operatorname H\) 是极差,初始条件 \(f_0 = 1\)。
这个式子因为要枚举 \(j\) 且 \(\operatorname H\) 值随着 \(j\) 的变化而变化,所以很难用什么东西直接维护。观察一下贡献的本质是什么,可以发现一个 \(f_j\) 的值在区间最大值增加 \(x\) 的时候对后面的贡献增加了 \(f_j \times x\),最小值减少的时候同理。那么可以开一个值域线段树,把 \(f_i\) 挂到当前的区间最大值上面去,当区间最大值变得更大的时候计算比它小的对它产生的贡献即可。
-
夜深人静交了一发 P5397,发现还是只能 90。
-
卡常没有意义!/fn
Day -90
- 省选计划模拟赛
- A。容易想到枚举答案看对于哪些成立,经典的中位数 +1 -1 trick,每次修改暴力更新所有祖先的 dp 值即可,因为完全二叉树高是 \(\log\) 级别的,所以复杂度是对的。这我居然没有想到 /dk。主要是当时想着直接大力 dp 没想到这个经典 trick 了。
- exA,上一般树。建出点分树在点分树上做即可。
- 剩下都不会了 /ll
Day -89
- P4556,线段树合并。递归时要注意是当前点左儿子为空时用新加进来的覆盖,而不是非都有即覆盖。
- 洛谷省选计划 #4 C。讲到过那个用一些东西表示另一些东西的判断其实就是插入线性基,所以对线性基略做修改,判下 \(x\) 插入后 \(y\) 是否完全插入(否则无解)即可。最后的答案就是线性基中空的地方随便填。
- CF741D,dsu on tree。重新排列能回文就是至多只能有一个字符出现奇数次。字符集大小只有 \(22\) 所以状压成一个二进制数,那么就要求长度最大的异或后 \(\operatorname{popcount}\) 只有 \(1\) 的。考虑暴力计算,开一个大小为 \(2^{23}\) 的桶,对于每个点为一个端点的直接计算,对于跨越其两个子树的就挨个子树计算与前面的贡献并更新桶的答案。把这个暴力换成 dsu on tree 即可。注意使用桶之前要判断该位置上是否有东西,以及一些单独更新的要更新全。
- CF1520F2,二分。直接二分是不行的,因为 \(t \log n\) 的询问次数超过了上限。考虑把序列分块以后先获得到每一块的前缀和答案,二分到块里之后再二分地询问。询问次数是 \(\frac{n}{B} + t \lceil \log_2 B\rceil\),取 \(8\) 最优,只需要 \(5.5 \times 10^4\) 次询问。注意这里二分不能写通常那种二分,因为那样询问会多一次,得写询问区间是 \([l, r)\) 然后若 \(mid\) 成立则 \(r \leftarrow mid\) 否则 \(l \leftarrow mid + 1\) 的二分。
- CF1515E,dp。直接进行 dp 比较困难,考虑最后手工开的状态是怎么样的,肯定是若干个连续段中间隔着一个。那么设 \(f(i, j)\) 是前 \(i\) 个有 \(j\) 个时手工开的方案数。\(f(i, j) = \sum f(i-k-1, j-k) \times 2^{k-1} \times {j \choose k}\),即枚举最后一次手工开了多少个,然后再乘上开这些的方案数(每次可以选择左边加一或右边加一),再从 \(j\) 次操作中选出 \(k\) 个位置进行。初始条件 \(f(i, i) = 2^{i-1}\)
倒计时似乎应更新至 -83
Day -83
- CF1503C,dp。这个 \(c\) 肯定是要加上的,所以考虑 \(\max\{0, a_j - a_i - c_i\}\) 最小。对于一堆东西的到达关系,如果有一个是其它的不加费用都到达不了的,那肯定是要把前面最接近的一个排在他前面,以此类推。所以将 \(a_i\) 排序(构造出的方案是循环的,所以做的时候不一定要从 \(1\) 开始),找出前面最大的 \(a_i + c_i\) 看能否到达一个点,不能则计算贡献,否则直接跳过。这样子是正确的,因为从 \(a\) 大的到 \(a\) 小的是无论如何都不会产生贡献的,所以若一个最大值要服务多个值,直接先跳到最后再往前即可。
- CF1500B,数论。因为一个数组中的互不相同,所以可以直接存储下对应关系,现在我们要知道一个在重复几次后会第一次产生对应关系,这样二分之后除一除就可以了。设在第一个序列中出现在 \(x\) 对应 \(y\),那么 \(pn + x = qm + y\) 移项得 \(pn - qm = y - x\),用扩展欧几里得算法就可以了。注意负数不能直接取绝对值,要搞成模意义下负数!
- CF765F,线段树。只需考虑后面比前面小的情况,另一种情况取反值域后再做一遍即可。对于一个数 \(a_i\) 找到前面最近的大于它的 \(a_j\),构成一个可能的数对。然后再找 \(j'\) 时,必须满足 \(a_j-a_{j'} > a_{j'} - a_i\) 不然 \(a_j\) 和 \(a_j'\) 产生的数对显然更优。那么 \(a_{j'} < \frac{a_i+a_j}{2}\),只有 \(\log V\) 对。离线下来权值线段树维护。注意取反不要用负,容易破坏取整的性质,用大数去减!。
- CF1498E,竞赛图。竞赛图的经典性质是缩成若干个强联通分量后每个强联通分量中的的向后面的所有点都有连边。这样一来前面的点入度一定严格小于后面的。那么按照入度排序后强联通分量肯定是连续的。事实上,当且仅当一个点之前所有的入度和 \(\sum a_j\) 等于 \(i \choose 2\) 时可以分割开来。当且仅当这样时后面没有向前面连边,但所有前面的点之间的边都会对入度和产生贡献。所以不需要询问直接做就可以了。
- CF150E,点分治。二分后改边权进行点分治,用俩数组维护之前子树某深度的最大值,和当前子树某个深度的最大值。然后枚举当前选几个,就是要在另一个数组中求一段的最大值。单调队列可以解决。但是这样要合并子树个数次,复杂度太高,需要启发式合并。注意,启发式合并用的最大深度需要新处理,不能再找重心时处理,因为树根会变。
Day -82
- 上面那题记得把剪枝减满,两只 \(\log\) 跑得有些慢的。
- 学校模拟赛
- B。推了莫反式子其实大可不必,那个求和 \([\gcd = 1]\) 的就是 \(\varphi\)。不过很高兴第一次在比赛中成功推莫反式子。
- CF
- 见鬼了,卡 C。
- OI 生涯至暗时刻:不会 Div.2 C
Day -81
- CF1498D,dp。一个朴素的想法是状态里记下前几个哪个是否可行,但这样要枚举转移是 \(n^2\) 的。实际上这样有很多不必要的花费,因为在某一步中到达某一个所有的都是一样的,只要步数不超过限制就行。所以开一个 \(g(j)\) 表示当前到达 \(j\) 需要新增几步,因为所有转移都是从小到达的,所以可以直接更新。
- CF613D,虚树。模板。
- UVA437,dp。把每个长方体拆成三份,因为肯定是从面积严格大的到严格小的,排序后直接 dp 就行了,不用建 DAG。
- AT2336,2-SAT。二分之后就变成了一段不能和一个连,可以线段树优化建图后跑 2-SAT。具体地,开一排假点,实际代表这个位置上的点的另一种状态,然后对着一堆假点线段树优化建图。
- CF1450E,差分约束。直接按照差不超过 \(1\) 的限制差分约束然后再验证就可以判断。因为如果一条边长度是 \(0\) 那么 \(1 \to x \to y \to 1\) 构成奇环,而奇环是肯定不行的。
- CF1000F,线段树。先离线下来,然后就是要对于一段看它上一次出现是什么,在不在查询的之前。注意第二次出现要把前面一次出现设为无穷,不然就把这俩一样的视为不一样的了。
- OI 生涯至暗时刻 \(\times 2\):不会小白月赛 B
Day -80
- CF1486E,分层图。直接五十一层分层图就行。 5e6 能跑过。
- CF919E,数论。\(a^x\) 循环节是是 \(p-1\) 的,前面那个循环节是 \(p\) 的,把式子对 \(p-1\) 做带余除法,然后就可以把所有东西都将到 \(p\) 以内了,可以直接枚举 \(x \bmod p\)。
- P4630,圆方树。模板。
- P2155,数论。\(\varphi(m)\) 可以通过递推解决,是质数按照积性函数乘 \(i-1\) 否则乘 \(i\) 即可,因为质因数分解没有变化。
- P4606,圆方树。答案是圆方树上关键点最小导出子图中的关键点数量。把点权化成边权,按照 dfs 序对输入排序然后计算相邻两个间的圆点数再除以二就可以了,但是会漏掉最顶上的一个 lca,特判即可。
- 注意跳点与加贡献的先后
- 点权转边权后只会少算最顶上的一个 lca
- CF1485D,构造。因为限制是相邻的,所以进行黑白染色,黑点放一个所有点的公倍数白点减去当前位置即可、
- CF1477C,构造。每次连最远的,再下一个点一定与上一个点同侧,不然和最远相矛盾。
- CF1474D。设 \(p_i\) 是 \(i\) 和前面一个操作次数,\(q_i\) 是和后面一个。那么 \(p_{i+1} = q_i, q_1 =a_1, p_n = a_n\),这样若合法则每一项都可以递推出来。那么 \(f\) 是从前往后的 \(p\) 值,\(g\) 是从后往前的 \(g\) 值,合法当且仅当一个位置满足 \(f_{i+1} = g_i\),枚举每一个交换看是否成立即可。
只有不到 80 天了,状态还是好差 /dk
Day -79
- 校内模拟赛
- A 看了两个半小时一点不会,B 暴力 C 退火,成功垫底。
- A 直接 dp 会有后效性,因为从后面会连到前面,所以不满足无后效性,但是对于肯定不会被相差超过 \(B\) 的位置影响,所以对于 \(B < 20\) 可以状压。这应该想到的。
- CF round 766
- A、B、C 还算顺利。
- D 想到了关键转化,但对于“一个集合中有一个子集 \(\gcd\) 则整个集合 \(\gcd\) 为 \(1\) 却卡了很久。 /kk
Day -78
- 省选计划模拟赛
- 没有状态,注意力太不集中了。
- A 数位 dp + 跳 kmp next,不处理好哪一位会跳到哪会多一只 \(\log\) 于是 \(100 \to 95\)。
- C 忽略了 \(\sum p_i = 1\) 的性质,也没有把合并的式子拆开。
- CF1470D,思维。考虑向一个已经连通的集合中加入新点,如果已经有和新点相连的黑点,那新点就不用染黑了,否则一定染黑。注意条件是要连通的集合,所以得通过 bfs 做。
Day -77
- 省选计划模拟赛 #6 C。
- CF1468H,思维。结论是有一个满足左边和右边都超过 \(\frac{k}{2}\) 且 \((k-1) | (n-m)\) 就可以。因为那个左边右边对 \(\frac{k}{2}\) 取模的和在模意义下肯定是 \(0\) 所以存在一种方式删至左边右边都是 \(\frac{k}{2}\) 个。
- CF1468A,dp。考虑其中的不下降序列,那么可以有 \(n^2\) 的 dp 做法。\(f_i\) 表示到 \(i\) 结尾且 \(a_i\) 是不下降序列的结尾,那么如果两个决策点之间有大于当前的则转移可以加二,否则只能加 \(1\),因为前面一段加二的肯定比该段加一的时候大,所以可以直接用树状数组维护前缀最大值。从小到大的限制排序后加入点就可以了。
- P4563,dp。挺好的题!首先肯定是在最右边放上一个,然后设不能看到的点是 \(p_1, p_2, \cdots, p_k\) ,那么可以把中间的答案都加起来再加上左边的,可以发现除了左边的其它段都是一直不变的,且和就相当于 \(f_{p+1, j}\),那么就很好转移了。
- CF1467D,dp。注意了,经过这个点不能通过这个点出发的乘个 \(2\) 之类的得到,因为到这个点的方式是不确定的,不知道中间有没有只加一次的,所以得通过到这的和从这出发的拼出经过这个点的方案来。
- P3736,dp。考虑 dp 的时候我在想怎样才可以用状态描述有前导零的状压以及在不大的复杂度内覆盖所有情况,但在这个问题中,只需要考虑答案的最后一个字符如何加入就行了,最后一个字符可以由 \(1\) 个合并成,也可以由 \(k, 2k, \cdots\) 个合并成,所以再区间 dp 时枚举中间的断点,考虑把右边拼进左边就可以了(具体来说就是从右边界开始一直减去 \(k-1\))。
Day -76
- SP5446,弦图。弦图的基础,MCS 算法的模板,每次找未标号的和已标号的点相连最多的然后将标号序列倒过来即可,证明不会。
- CF1461E。对于 \(x > y\) 的情况肯定每次都加,看几次之后撑不下去即可。对于其它情况肯定是一直减 \(x\) 直到不能减了再尝试加,事实上我们发现除了 \(x\) 其它数据都特别小,而这个减的过程中一次完整的减过去后 \(k \bmod x\) 一样的都是一样的状态,所以若发现循环就可以直接退出了。
- P4067,dp。不会数位 dp /kk。\(f(i, 1/0, 1/0, 1/0)\) 表示填到第 \(i\) 位,横坐标 \(i\) 前面的位是否严格和 \(n\) 相等,纵坐标 \(i\) 位之前是否和 \(m\) 相等,以及答案的 \(i\) 位之前是否和 \(j\) 相等的和。转移的时候枚举当前一位横纵各是什么,以及下一位该是什么,如果是比 \(k\) 大了,那么就减掉 \(k\) 的这一位,用我为人人型 dp 很好写。
- CF1438D。这样的操作不会改变异或和,所以偶数个肯定异或和是 \(0\),不然就无解了。而如果异或和是 \(0\),那么去掉最后一个剩下的异或和就和最后一个相等,所以只要解决奇数的情况就可以了。手玩玩即可得出奇数情况。做这题的时候在考虑按位处理,但题目要求 \(n\) 步以内,按位处理肯定是不合适的。
- CF1437E,dp。按照固定的分段,看每一段中最多固定的,转移满足的条件有 \(a_i - i \ge a_j - j, a_i \ge a_j, i > j\) 其实一三两条就已经把第二条包含了,那么直接最长不下降子序列即可。
- P4124。用记忆化搜索实现的数位 dp。非常好写,只要枚举当前是什么看状态有什么变化即可。
- CF1428E。https://www.luogu.com.cn/blog/Qiaoqia/solution-cf1428e,这性质证明还挺妙的。
- P3254,最大流。从源点往单位连流量为人数的边,然后每个单位往每张桌连流量为 \(1\) 的边,每张桌往汇点连流量为桌子上人数限制的边跑最大流即可。
Day -75
- P3561,竞赛图。竞赛图上构造哈密顿回路和哈密顿通路是多项式时间的。本题构造出每个 SCC 的哈密顿回路,对于每个询问在所在强联通分量跑一圈再到下一个即可。
- CF1627E,dp。上场 CF 上分的好机会啊,可惜居然卡 D 没做出 E /dk。首先肯定不需要 \(n\cdot m\) 级别的点,只需要把用到的保留下来即可,然后肯定不会在一层中间来回走,所以 dp 的时候每一层从左到右从右往左算一下就可以了。
- CF1622E。因为 \(n\) 才 \(10\),所以可以枚举哪一些 \(r_i - x_i\) 为正,哪一些为负,确定之后每一个值对答案的贡献也就确定了,把最大的值分给贡献最大的,依次分下去即可。
- CF1616E。Good Bye 2021 的 E,居然卡了我一下午。问题的关键在于怎么处理偏移量,我做的时候在原来的每个点上记下偏移量,这是错误的,因为从要偏移的区间外移动到区间内的点会漏掉。其实非常简单,只要记每个原来的位置之后有多少个点被移调了即可。因为移掉的点肯定不会再用到了,而剩下的点肯定后面每移掉一个就会后移一个。
- 产生和销毁内存也是要线性时间的,所以多测不能每次局部开 n 的数组。
- 一定要想清楚了再去写啊啊啊!
- CF1425E。分讨题。按照 \(k\) 讨论。
- CF1625D,dp。看样子我错过了两次上分好机会,这场离谱,居然卡 C /ll。排序后相邻的异或都不小于 \(k\) 就是满足要求的充要条件,所以可以 \(n^2\) 的 dp。然后把 dp 值挂到 trie 上就好了。代码很好写。
Day -74
- P4363,dp。局面肯定是从上往下长度单调减的,那么可以用最初若干个 \(1\) 然后后面隔一个 \(0\) 后面多少个 \(1\) 表示减去多少来表示整个状态,这个二进制数不超过 \(2n\) 位,所以状态数最多只有 \(10^6\) 级别(实际上还更少,因为很多状态比如全 \(1\) 是不合法的),那么直接记忆化搜索就可以了。
- P5369,dp。枚举构成那个最大点集合,那么就要求该集合组成最大前缀和为其中所有数的方案数,以及后面的前缀和都不会大于 \(0\) 的方案数。后者很好做,前者考虑把一个数差到最前面,那么后面的和不能为负,否则就全扔掉了,所以对于 \(sum(S) \ge 0\) 贡献 \(f(S \cup \{i\}) \leftarrow f(S)\) 即可。
- AT2069。注意有 \(0\) 边时用 Dijkstra 转移 dp 之类的是错误的,因为更新 \(0\) 边并不会使节点重新入队。
- CF1415E。没有想到关键的一点:插入一个新的时候不管加入哪个下一次要加的都会减少那么多,所以插进最大的里面一定是不劣的。
- CF1407D,单调栈。单调栈也不会 /dk。对于第二个限制如果后面隔了一个更大的肯定不行,所以维护一个递减的单调栈,弹出的时候更新 dp。
- CF1406D。难得的自己做出
*2200
!考虑 \(a\) 相邻之间差和 \(b、 c\) 差的关系,容易得到后两者的和等于前者,那么限制了一个时另一个也就随之确定了。而一个的限制就是小于等于 \(0\) 且小于等于 \(a\) 相邻差。用这个判定二分出来的答案是否成立即可。 - CF1400E。一次只减去一段不如把整个能减的区间都减了更优,递归下去做即可。
Day -73
- 花赛
- 一看 C 不会,引起了我的兴趣,不过经过一定思考后还是切掉了 /cy。然后因为没注意到 \(10^0 = 1\) 挂大分。/dk
- 洛谷月赛。
- B 还是有些细节的,没想到居然能写完并没调多久就出来,开心。
- 然后一晚上啥也没干成。
Day -72
- 阅读了 Um_nik 的 How to practice Competitive Programming 于是开始了不看题解的做题生活。
- CF1398E。如果那些特殊数字不是恰好是最大的几个的话那么肯定可以构造出把最大的都取上的,否则不行,因为 \(n\) 个点 \(n\) 条边肯定会出现环,这种情况下取略小的一个就可以了。用
std::set
维护。有很多的细节,调了很久。 - CF1389E。题目可以简化成 \((x - y)(d-1) \equiv p \pmod w\) 且满足 \(x, y \le k\) 的无序二元组 \((x, y)\) 的数量。先把 \(w\) 和 \(d-1\) 中除去它们的最大公约数,问题转化成了 \(x - y\) 是某一个数 \(g\) 的倍数的数对数量。只需要对于每一个对 \(g\) 取模的余数统计有多少个范围内的数字和它相距了 \(g\)。这个个数只有两种取值。
- CF1384B2。如果不是完全覆盖,肯定不要停留了直接走,否则停留直到循环到下一个最早的时刻。这样肯定是最优的。
- CF1373E。最多只会进位一次,那么枚举是否进位、在加第几次的时候进位即可。注意一些细节。
- 虽然实现了不看题解,但是若干细节题每一道都要调很久,希望开始写之前要考虑清楚。。
Day -71
- CF1353F。如果 \((1, 1)\) 的值确定了,后面每一个位置要在路径中的值就确定了,直接 dp 即可。所以枚举 \((1, 1)\) 的值,容易发现只有恰好让某一个合法的值是最优的。
- WC 讲课
- 似乎讲得挺好的?
还是啥都没听懂
- 似乎讲得挺好的?
- 省选计划模拟赛
- 想了很久 T1 啥也没想出,写了 \(60\) 分跑路,最后没取模挂成 \(45\) /dk
- 生成函数 /yun
- CF1338C。两位的时候只有 \(1, 2, 3\) 能够被消掉,然后就只能在前面多加两位了,因为如果只加一位必然会出现重复。最高的两位确定后后面就可以随便排列(错排),每一位只有 \(4\) 种取值。确定最高位之后按四进制分解就可以了。
- ABC236.
在完成前三题后编写 D 题之前未计算复杂度,获得 TLE 的结果后仍未计算复杂度,反而忽视问题并不具备最优子结构性质,盲目尝试其它做法,未分析算法中所存在的重复和不必要,浪费大量时间。随后执行跳过程序,转向 E。在 E 中同样在编写之前未考虑实现细节,获得 WA 的结果后仍未思考实现细节,只是不停的胡乱改代码。最终获得了 rk2088 这一 2021/3/13 以来的最差成绩,构成严重事故征候。
调查结果表明,在此次比赛中,我没有遵守标准程序,追求快速而没有执行计算复杂度、考虑实现细节等检查,在遇到问题后没有沉着冷静考虑解决方案,反而乱了阵脚,进入了失速状态未成功改出,最终造成严重事故征候。
改进建议:在平时的训练中严格执行标准程序,实现前考虑清楚实现细节,预防进入失速。在出现问题后切忌盲目修改,一定要保持冷静,尝试改出,分析出问题所在并执行检查单确认无误后再进行修改。并加强赛时模式下的训练,定期进行 vp。
——《关于 2022-1-13 ABC236 严重事故征候的调查报告》
- 打完 ABC 过于伤心以至于没有关 CVR 造成数据丢失。
Day -70
- CF1335F。第一问的答案肯定是要吧环都选满。第二问需要考虑怎么处理冲突的问题。随便选一个点作为关键点,其它都和它求个距离对环的大小取模即可。还是想了有点久时间的。
- CF1333F。先考虑互质的数最多选多少。如果选了一个那么其约数和倍数都不能选了,所以肯定是选质数最优。然后考虑 \(\gcd\) 不等于 \(1\) 的情况,就相当于乘上去的数要互质且最多,那肯定是要质数。但这样会出现重复筛一个的情况,而重复筛了的时候肯定是最大的那个约数为答案,可以像欧拉筛一样筛到和当前数不互质的质数就退出。
- CF1328F。读题!这题是只能改最大和最小,所以枚举最后到达的那个数,如果要从左边贡献,那么所有的数都要到和它差一的地方预位,右边同理。
- CF1327D。做了一下午的题啊啊啊啊,好在最后还是独立做出了。开心!可以发现置换的幂次就是每个数在它所在的环里依次换过去,而对环中颜色相同的要求的那条边一开始是移动的反向,而每经过一次置换都被拉长了 \(1\)。那么问题就变成了找到最小的 \(k\) 满足存在一个步长和一个位置每次循环跳这个步长所经过的点都是同一种颜色的。由裴蜀定理可以知道两个点在一个环里当且仅当两个点的差是步长和环长最大公约数的倍速。那么所有最大公约数相同的步长其实就是等价的,枚举环长的约数暴力跳即可。
- CF1305E。看上去很吓人的构造题。看到题之后想着 \(m\) 那么大 \(n\) 那么小以为是啥指数之类的构造。其实容易得到上界,就是对于每一个 \(k\) 前面的每一个值都参与贡献,因为一个值贡献一个位置不可能贡献两次,所以这样就是最大值了。满足这个要求很简单,\(1, 2, 3, \cdots\) 即可。然后考虑减掉一个,就是把最后一个加一,那么能达到它的视之前达到它的个数减去 \(1\)。到完全没有用的时候扔到值域的末尾并减去 \(5000 \times 2\) 即可(因为前面可能会加出 \(5000 - 1 + 5000 - 2\) 出来。
- 不错的一天。
Day -69
- CF1303E。一个简单的状态是 \(f(i, j, k)\) 表示前 \(i\) 个,前面匹配到 \(j\) 个,后面匹配到 \(k\) 个是否可行。但这样加上枚举端点复杂度就变成 \(n^4\) 的了。因为前面肯定越早匹配越好,所以把状态改成 \(f(i, j)\) 表示前面匹配到 \(i\) 个,后面最多能匹配到多少个。注意初始条件和边界情况。
- 花赛
- 看错题 + 看错题。
- 类似表达式求值的东西尝试写了 lexer parser 成功爆炸。
- CF1295E。枚举开始时一边有几个不太好做,所以枚举最后一边有几个,然后考虑枚举开始时一边有几个,断点在最左边的时候代价肯定是最后要到左边的,随后最后要到左边的贡献负的,右边的贡献正的,求最小前缀和即可。可以用线段树做。这题做得还挺顺利的。
- CF1278E。做了半下午加整个晚自修四个多小时都没做出来。/dk
- 于是问了 Um_nik 我啥时候该放弃,结果得到回复了!
- 看了 -is-this-fft- 的 Self-deception: maybe why you're still grey after practicing every day 后又觉得不该放弃了。
- 于是做到最后也没有过。
- 于是问了 Um_nik 我啥时候该放弃,结果得到回复了!
Day -68
- 一早起来总结了一下昨天忽略的地方,好耶!过了!原来昨天把能让我想不出的方向都试了个遍。
Day -54
为什么突然就跳到 Day -54 了呢?
为啥突然从 Day -454 跳到 Day -54 了呢?
今天不错,希望最后的 54 天能是真正 OI 的 54 天。
Day -53
没遇到什么有趣的题。
到处都是无聊的细节卡很久。
Day -52
卡细节的情况少多了。不过节奏太慢,不太有感觉。
有趣的题
- CF1552E
Day -51
- 校内模拟赛
A, C 确实做不了,但 B 没有想到这个 50pts 的二分有些可惜了,考虑首尾的时候想到了两个不超过一半一定可取,却没想到中间也是这个样子。这题挺好的。https://codeforces.com/gym/102268/problem/B - Mivik Round
B(P8149) 挺有意思的一题。赛时虽然想到了启发式合并,总共最多被检查 \(m \log n\) 次,但是却没有想到直接去检查输入的条件,而是对于整个连通块的出边在检查,这样就多了很多没必要的情况,复杂度就假了。 - 出乎意料的 CF1648M。
没有考虑过根号分治,其实这种输入规模加起来等于啥然后又可以一个和剩下所有暴力检查的应该想到根号分治的,因为超过根号的段不超过根号个。
Day -50
- PMOI
不错的比赛体验!B 是个好题,想了好久想出了一个细节特多的做法。还是出题人的贪心做法比较好些一些。C 没想到随机撒平面就给过了,居然才那么点人过( - CF1425D 想不到容斥 /kk
Day -49
- 白天不错的做题体验啊,就是下午好像有点晕乎乎的,对着二十行代码调了俩小时。
- Codeforces Round #771 (Div.2)
- 很棒的比赛体验!
- A 4min B 7min 好家伙又给卡 C 了,到一小时才过,怎么老是卡 Div.2 C 啊啊啊,过的时候都 rk1700 难道又是下大分的一天了吗。
- 这 D 咋比 C 还简单,二十分钟多一点给切了。
- 燃起来了,燃起来了,最后 35min 挑战一个 E。好耶这个 E 好像相对简单了,最后 15min 的时候想出了个做法!哇哇哇激素调节的感觉来了,赶紧写最后 4min 写完一遍过了样例。
所以耗时最多的题是 C? - 啊啊啊怎么交不上啊,什么鬼,这 submit 怎么按不下去,怎么 403 了,备用站备用站,备用站地址是什么啊。
- https://codeforces.com/blog/entry/99942?#comment-886913
- 遗憾离场。第二天发现交上去了也是 re on 4,把一个单点改查前缀和的写成区间改求单点的了。
所以不可惜。 - 不过做出了只有 77 个 rated 的过的 E 了还是很开心。XD
- 情人节 \(\color{red} \times\)
“翘翘要越来越棒!” \(\color{green} \checkmark\)
这似乎是 400 天来最棒的一周耶!
Day -48
今天晚上状态不好。
多重集哈希要加而不要异或,不然一个值出现偶数次就没了。
Day -44
这周状态好像都不是很好。
Day -43
OHHHHHHH!
早上晕乎乎的,没有做啥题,晚上卡一道数位 dp 了。
为什么我永远做不出数位 dp /fn。
Day -36
- 有意思的题 CF1172C1,在操作序列前面增加操作而不是后面。
Day -33
- 有意思的题 CF1131E:倒过来考虑。
Day -29
CF1634E 巧妙地(特别是二分图的做法,太棒了)转化为图论问题。
将每一行 \(2i\) 和 \(2i-1\) 连边,每种颜色第 \(2i\) 和 \(2i-1\) 连边,这样一定是二分图,因为不可能有奇环。
对这个二分图染色可以保证每一行和每一种颜色都是恰好一半选到。
CF 770 是什么神仙场啊啊啊,B, E 两道都好棒啊!D 虽然难写点但也很不错!
Day -28
CF1630D,巧妙地将任意一段转换成了开头一段再取反相距 \(L\) 的两段。
Day -13
前一段时间似乎又倒回到大部分要看题解的状态了,今天非常好地保持了几乎独立思考,只在思考一晚上未果时瞄了一眼题解并独立完成了其它部分(所有要用到的性质都想到了啊啊啊)。
省选可能会延期,那么有可能能上 IM?
Day -12
[BalticOI 2021 Day2] The short shank 好题!
Day -11
有趣的思维题,CF1373F,做了好久。https://www.luogu.com.cn/blog/Qiaoqia/solution-cf1373f
Day 2?
转眼间 133 天就过去了啊。
Day 8?
1583F,神仙构造!
Day -19
后缀排序多测得清空 tp 和 rk,因为 tp[sa[i] + w] 时可能会用到超出的。所以空间得开两倍。模板题数据不够强啊。
Day -15
最后 15 天了,好好度过 OI 生涯的最后时光吧。
Day -8
CF1427E 什么神仙题啊,这怎么想得到,亏我花了三个小时。
上午想那构造没有任何进展,下午啥事没干,晚上在 SWERC。
只剩下最后一周了。
Day -6
为什么想到根号分治却想不到最简单的情况 /fn
为什么多了一个解引用要调那么久 /fn
Day -4
- 第一次真正叉人,而不是叉哈希和伪随机数 /cy
- 小清新题 CF1332F,把上面不连的情况合并起来考虑其实挺妙的,想也想不到。不过看了题解之后就觉得“我是傻逼,这都想不出”了。
Day -1
结束了。
Day 0
中午吃完饭去学校集合前往海亮。
念心湖酒店真真是十分高级,ync 评价是“海亮国际机场”。考虑到 WIFI 密码,我决定把这的 IATA 代码定为 NXH。
二次元老大 z 宝一进房间立即开始外放二次元,我忙尝试连了一波 WIFI,然后发现手机连了电脑就不能连了?
随后 sigma 主持召开省选期间工作会议,她指出,海亮只提供早餐,中餐晚餐要付钱,为了吃得好一点我们可以点外卖;
她强调,因为考试时间长,最好能带一些零食吃,没有带零食的可以和袁老师一起去买一点。
于是我们认真学习 sigma 讲话精神,和 hjyuanrl 去买吃的了,来到了某面包店,老板表示他有券,我们可以一起买,再转钱给他,于是我们就把原价减去可省的转给他了,老板大呼亏了。
晚上吃了一碗炒饭,颓了会儿 B 站,请教了一下 pigstd,把昨天月赛要补的一道题写了,又写了一道比较水的 cf *2500,就睡了。
Day 1
比赛开始前发现键盘某个键很卡,就换了一个。
按照 ZJOI T2 最简单定律,果断开 T2,很快想出了 40pts 做法,然后敏锐地发现了可以根号分治,想出了一个部分,很快又想出了另一部分。
然后发现做法假了,但看着这个众数,毛咕估,根号分治是不会有问题的,于是就决定继续想一会儿。
接着……比赛就结束了……比赛结束前把阈值调成了零并瞎写了另外两题的暴力,就遗憾离场了。
出场问了 Froggy 根号分治的另一种怎么做,听上去挺可做的样子。
下午就颓颓颓颓颓。
晚上来了一个我从未经历过的聚餐,还蛮开心的,印象最深的是“我钦定这个给磁暴”。
聚餐回来后 sigma 就第一天比赛情况发表谈话,sigma 指出,大家都比得挺不错的,明天加油。我翻了翻《四班群星闪耀时》,觉得有些凄凉。
Day 2
早上有一堆小朋友。
发现 t2、t3 暴力都不是很好写,就写了个 t1 矩阵快速幂的暴力,然后开始找规律,找来找去最后只发现了个 \(2^n\) 的规律,拼一下包大概是 30pts?
然后又双叒叕遗憾离场了。出场时走出海亮山中凹下去的一层,光线一下子刺眼起来,或许算法竞赛以外,有着更光明的天地吧。
他们说的退役太沉重 / 你在路上追着你的梦 / 一切会与过往不同 / 但精彩纷呈。
然后便是发出由《落幕》修改来的《退役》,一晃就回到了学校。
跑步时因为运动腹痛而备降了,下午吃饭太晚,晚上吃完了 Day0 买的饼干,胡乱学了学物理就过去了。
从此,便不再是 OIer 了。
2022.8.5 定稿。