2025.7
-
2025/7/1
上午学习启发式合并。完成 CF600E,
CF600E 注意开 longlong,以及函数调用别调用错了。因为子树之间互相没有关联,所以处理完一个子树后要清空再处理其它子树,暴力清空即可。对于最大的一个子树,可以选择最后处理,这样就不用清空,可以直接再把之前的子树加回来,能够节省时间。
下午写 CF1996。A 3分钟;B 4分钟;C 13分钟;D 10分钟;E 20分钟,注意要给 \(sumx_0\) 初始化为 1,表示左端点为 1 的情况。
F,相当于在加一些等差数列,很多个等差数列要求前 k 大的数之和。于是二分第 k 大的数 m ,根据大于等于 m 的数的个数来调整 m 的大小。因为有可能有相等的数,导致没有正好 k 个数的方案。所以要么算使得个数小于等于 k 的最小 m,要么算使得个数大于等于 k 的最大 m。如果用前种方法,可能会小于 k,就还需要计算应该加哪些数。后种方法需要减的数一定是 m,更好处理。其中,计算当前等差数列大于等于 m 的数的个数时,不能写 \((a_i-m)/b_i+1\),要写 \((b_i+a_i-m)/b_i\),因为 \(a_i-m\) 可能是负数。
G,暴力想到枚举每一对点走左边还是右边,有两条边的原因是它是个环,所以想到删去一条边使得它变成一条链,这样在这种情况下答案就是唯一的。枚举删哪条边,在变化的时候,如果当前删去的边对应的是某一段的左端点,那它原来走的是中间的路,要变为两边。如果删去的边对应的是某一段的右端点,那它原来走的是两面的路,要变为中间。用线段树维护被覆盖的也就是要维护的路的数量。
-
2025/7/2
上午学习倍增。
下午写 CF2106。A 4分钟;B 3分钟;C 15分钟,注意 b 全是 -1 的算法,和的上界不是 k ,是 minn+k;D 25分钟,没有判断 b 的指针是否超出边界,以及 ans 的初始值不能是 1e9 ,因为 \(b_i\) 可以是 1e9。
E,因为 k 的位置是不变的,所以查找到 k 的路径固定,可以算出路径上需要的小于 k 的数的个数 x,和大于 k 的数的个数 y,优先路径上的点互换,再动不在路径上的点。通过比较所有小于和大于 k 的数的个数与 x 和 y 的大小来判断是否合法。
F,首先看出来题目在求 0 的最大连通块大小。其次竖着看,发现每一列只会有一个点与其他点不同。如果这个点原先是 0,那么这列的 1 会把 0 分成上下两部分,上半部分与之前的上部分联通,下半部分与之前的下部分联通;如果是 1,那只会有一个点可能跟之前的 0 联通,联通后,对于下一列,它所在的连通块属于上半部分。所以将上半部分更新为下半部分加一,清空下半部分。在算的过程中更新答案。
-
2025/7/3
上午学习倍增,完成 CF1878E。
下午写 CF2121。A 8分钟;B 8分钟;C 16分钟;D 20分钟;E 30分钟;F,注意开 longlong,对于最大值的限制,记录最近一个 x 和大于 x 的数的位置,在这两个位置中间的左端点可取。
G,由 x、y 较大值为 (x+y+|x-y|)/2 ,可将答案分为 x+y 和 |x-y| 两部分。x+y 部分就是所有子串长度之和,|x-y| 部分想到把 01 用 -1 和 1 表示做前缀和。所有有关绝对值的做法都是分类讨论。把所有前缀和放在数轴上看,讨论 x > y 和 y > x 两种情况。设当前前缀和为 p,维护小于 p 的前缀和的个数 cnt 和总和 sum,每多加一个 0 或 1,p 在数轴上的位置会左移一位或右移一位,动态维护 cnt 和 sum。大于 p 的情况同理。
-
2025/7/4
上午学习数位 dp,完成 P2657,P4124。
下午写 CF2123。A 5分钟;B 5分钟;C 12分钟;D 其实想了挺久,在想怎么证明。
E 从计算每个 mex 可以通过哪些 k 得到方面想,对于每个 x 要成为 mex,k 都有上界和下界,至少要把 x 全删完,至多只让 0 到 x-1 各剩一个。所以答案每次只在 k 上给连续一段加一,用差分计算。
F 对于同一个质因数的倍数,它们之间可以互相调换。
G,看到 %k=m 就想到同余类,需要求 k 和 m 的 gcd。看到非递减想到贪心,每次取最小的。对于相邻两个数,只需要判断他们所在的同余类的大小,就能判断出当前是否要跳段。如果没有操作一,可以进行预处理,并且预处理只需要处理出同余类个数的级别。有操作一,每次改变一个数,只需要考虑对两边的影响,维护每个点跳段的情况。
-
2025/7/5
上午学习数位 dp,完成 CF628D,CF1036C。CF628D,pow 常数大,超过18位用不了,超过16位有精度误差,并且数位 dp 是每次考虑把前面的往前移再加进来一个数。
下午完成 CF2121G,CF1996G,CF2121H,abc413G。
CF2121H,最长非递减或上升等子序列都考虑每个长度 i 对应的序列最后一个数的最小值 \(d_i\),按长度排序的话 d 是不减的。每次新加一个数范围是 \(l\) 到 \(r\),可以全部枚举,但是发现每一个数 \(x\) 只会让第一个大于 \(x\) 的 \(d_i\) 更新到 \(x\),在同一个区间的 \(x\),也就是 \(d_i<x<d_{i+1}\),这段的 \(x\) 起到的效果都是使 \(d_{i+1}\) 更新为 \(x\)。所以如果枚举,也只需要枚举同种效果下最优的,也就是每个 \(d_i\)。对于这一位,\(x\) 的选择仍然有很多,但不同的 \(x\) 对 \(d\) 的影响是同时存在的。如果希望这一位填这个 \(x\),那么后续就会取用这个 \(x\) 影响的状态。本质上是在同一个状态上因为不同的 \(x\) 产生了不同的状态,再将这些状态重叠起来看。
对于加进来的 \(d_i<x<d_{i+1}\) 的 \(x\),只会使 \(d_{i+1}\) 更新为 \(x\)。假设 \(d_a<r<d_{a+1}\) ,\(d_b<l<d_{b+1}\),所有 \(x\) 产生的影响相当于删去 \(d_{a+1}\),将 \(d_{b+1}\) 到 \(d_a\) 向右移一位,再在 \(d_{b+1}\) 位更新为 \(l\)。因为 \(d\) 始终不递减,所以用 multiset 维护,其大小就是答案。
-
2025/7/7
上午学习博弈,完成 CF859C,AT_dp_k,CF786A。
下午写 CF2117。A 5分钟;B 5分钟;C 13分钟,记录每个数组别的数组又开成 bool 了;D 24分钟;E 60分钟。
F,所有树上的问题,都是从叶子开始考虑。叶子只有两种取值,说明合法的树顶多两个叶子。先把多余两个叶子的情况排除。如果只有一个叶子答案就是 \(2^n\),因为父亲和儿子之间一定不冲突,父亲一定比儿子大。如果刚好是两个叶子,树一定只有一个节点有两个儿子,找到这个节点,考虑给它分出来的这两列填数。这个分叉点及其上面的节点都可以随便填,因为一定比下面大。
首先两个叶子一定是一个 \(1\) 一个 \(2\),如果要往上填,发现两列只能都填 \(2\),这样一列奇数一列偶数都不会相同。直到有一列已经填完,也就是继续往上就到了分叉点。这个时候再考虑较长列剩下的部分。
有两种情况,一种是较短的一列的叶子是 \(1\),一种是较长的一列的叶子是 \(1\)。前者,如果较短的一列填完,较长一列剩余没填的部分可以随便填,因为较长列填了的部分已经比较短列大,再填只会变大,不会有冲突的情况;后者,较长列再往上一个节点只能填 \(2\),如果填 \(1\),会跟这列的叶子节点的 \(1\) 加起来跟较短列的一个 \(2\) 抵消,会冲突。所以这个点只能填 \(2\),再往上的节点没有限制。这两种情况都要算进答案。当然如果两列长度一致,交换叶子节点的 \(1、2\) 后情况一样。
G,为了维护最长边,选择从小到大加边。注意不一定是简单路径,所以每次加的边所在的连通块里的点,互相可达,并且目前路径上可以经过的最长边就是当前加入的这条边。最小边跟最大边一样,也是同一个连通块里的点互相抵达的路径上可以经过的最短边就是这个连通块里的最短边,用额外的数组维护即可。并查集解决。在每一次加边后,都需要判断一下答案是否产生,也就是点 \(1\) 和 \(n\) 在不在同一个连通块里,如果在就更新答案。
即使有些边加入,\(1\) 到 \(n\) 没办法走到,更新答案时还把它作为最长边更新,也没有问题。因为如果没办法走到,就更不可能通过这条边走到更短的边,那么 \(minn_{F(i)}\) 不会变,而最大边更长,就是一个更劣的答案,不会被更新。如果它可以被走到,就可能会连到更短的边,所以是需要考虑的情况。
-
2025/7/8
上午学习博弈,完成 CF786A,CF1860C,CF1987D。
下午写 CF2114。A 5分钟;B 6分钟;C 6分钟;D 25分钟;E 50分钟。
F,要把 xy 变得一样,x 乘 a,就相当于 y 除以 a。所以问题转化为把 x 和 y 通过除以不超过 k 的数把它们都变成 gcd(x,y)。反过来看,就变成把 1 通过乘不超过 k 的数分别变成 x/gcd(x,y) 和 y/gcd(x,y) 需要的最少操作次数。dp 状态就是乘到 i 需要的最小次数。
G,要把问题转化为算可行的 k 的上界和下界。下界就是 n,因为保证了 \(a_i\) 不等于 \(a_{i+1}\),所以可以一个个加。为了算出上界,就需要考虑每个数最多可以通过加入多少个小数再合并出来。每个数都可以写成 \(2^c*b\) 的形式,需要把 \(2^c\) 分成小的数。理想情况下,每个数的分解过程或者说合并过程可以体现为一棵满二叉树。
先简化问题,考虑只能往右端加数的情况。为了不与前面的数合并,就不能出现后面和成前面的数的情况,就需要一个数挡在它们中间。如果前面的数出现在了之前说的满二叉树里,也就是合并的过程会碰到它,导致跟它合并。就需要树中它的父亲节点挡,这样就会损失父亲节点这棵子树。所以用这棵树的总大小减去这个子树的大小就能快速得出一个数最多能被分成多少个小的数。
再考虑两边都能加数,枚举第一个加的数是哪个,就又变成了两个只能由一边加数的问题,从而转化为前缀后缀的处理。第一个加的数没有限制,可以被完全地分解。
-
2025/7/9
上午学习博弈,完成 CF1970C2,CF2005E1,CF1033C。
下午写 CF2093。A 3分钟;B 6分钟;C 6分钟;D 55分钟;E 45分钟;F 贪心,随机实则就是要考虑最坏情况。
G,决定子数组是否满足要求的一对点一定在段的两端,多的数没有必要。可以枚举这对点,找到满足条件的最近的一对。优化目前的 n 方做法,枚举右端点,找到最近的左端点。01trie,由高位往低位填,如果 \(x \bigoplus y\) 二进制下第 \(i\) 位已经比 \(k\) 的第 \(i\) 位大,之后的位无论什么样都比 \(k\) 大。先考虑跟 \(k\) 的位反着填,如果可以,填到第一个使得值比 \(k\) 大的那位,在它这棵子树里找到对应的最大的 \(l\),之后再考虑正着填。如果反着填都不行,正着填更不行。
-
2025/7/10
上午学习 01trie,完成 P4551,CF706D,CF1285D。
下午写 CF2091。A 4分钟;B 6分钟;C 17分钟;D 6分钟;E 13分钟;F,注意同层转移要减去自己,以及再判断当前点是不是支点之前要把之前的前缀和传递过来,还有别搞错方向,是从下往上,还有减法取模每减一次都要加一次 kM。
G,看到 s 很大 k 很小,想到 s 大到一定程度就会有通解可以直接构造出来。\(s \geq k^2\) 时,如果 \(x\) 整除 k,可以直接跳到;否则往前走后回头一定能再走到一个位置距离 s 为 k-2 的倍数,答案就是 max(1,k-2)。\(s \leq k^2\) 时,暴力即可。\(d_{i,j}\) 表示步长为 \(i\) 是否可以走到 \(j\),转移枚举走多少步。
-
2025/7/11
上午学习 01trie,完成 CF1851F,CF2093G。
下午写 CF2060。A 5分钟;B 10分钟;C 11分钟;D 15分钟;E 40分钟。
F,观察到 \(k\) 较小,\(n\) 很大,所以数列里 \(1\) 的个数很多,非 \(1\) 的数字最多 \(log(k)\) 个。先不考虑 \(1\),\(dp\) 算出没有 \(1\) 的数列总数。\(d_{i,j}\) 表示乘积为 \(i\)、长度为 \(j\) 的数列个数。不考虑 \(1\) 的情况下 \(j\) 不超过 \(log(k)\)。
再考虑插入 \(1\),计算插入 \(1\) 的方案数再乘之前算出来的 \(d\)。设当前数列乘积为 \(i\),长为 \(j\),插入 \(1\) 后长度为 \(l\),方案数是 \(C^{j}_{l}\) 也可以说 \(C^{l-j}_{l}\)。
最终要求 \(d_{i,j}\) 的系数,也就是相同乘积所有总长度的方案和(插入的 \(1\) 个数不同),即 \(\sum_{l=0}^{n} C^{j}_{l}\),等于 \(C^{j+1}_{n+1}\)。设 \(a=n+1,b=j+1\)。
\(a\) 较大,\(b\) 较小,可以先把公式的 \(a!\) 和 \((a-b)!\) 抵消成 \(a*(a-1)*...*(a-b+1)\)。这部分暴力乘,分母剩下的 \(b!\),先预处理出 \(log(k)\) 范围内的逆元,然后也暴力乘。最后与 \(d_{i,j}\) 相乘,就算出了乘积为 \(i\)、长度在 \(1\) 到 \(n\) 内、非 \(1\) 个数为 \(j\) 的数列个数。枚举 \(j\),把不同 \(j\) 的方案数相加,得到乘积为 \(i\) 的数列个数。
G,把复杂的操作转化成一些简单的操作。发现只要列数大于等于三,列之间可以任意互换。假设是 \(i、j、k\) 三列,\(i、j\) 操作一次,\(j、k\) 操作一次,\(k、i\) 操作一次,列的顺序从原来的 \(i、j、k\) 变成了 \(i、k、j\)。
从操作来看,同一列的两个数不可能被换出去,列内部元素不变,只会上下交换。如果同一列要交换上下,需要带上另一列一起交换,所以交换上下需要的操作次数是偶数次。然后 \(dp\),\(d_{i,j,k}\) 表示考虑到第 \(i\) 列,列是否被交换上下,操作了奇数次还是偶数次。
-
2025/7/12
上午学习 01trie,完成。
下午写 CF2074。A 3分钟;B 5分钟;C 33分钟;D 40分钟。
E,因为没有三个点共线的情况,所以可以想到每次给出一个三角形内部的点,就将一个顶点缩到这个内部的点里,使三角形越来越小直到不包括别的点。但假设如果指定每次都是 \(x\) 缩小,次数会超。于是用随机数决定本次由 \(x、y、z\) 中的哪个点来缩。
内部的点 \(a\) 在不同点缩过来的情况下会造成下次询问的三种不同的三角形,相当于把由 \(x、y、z\) 构成的三角形分割成三个小三角。这三个三角形里,一定会有一个点内部的点总数小于等于大三角形的三分之一。随机到这个三角形的概率是三分之一,期望在 \(75\) 次里有 \(25\) 次会随机到这种三角形。\(n\) 总共就 \(1500\),缩 \(25\) 次三分之一是可以找到答案的。
-
2025/7/21
A
高位上大的答案一定更大,要尽可能让高位小。由于操作是按位或,当前答案小不代表后续答案也优。
从答案的高位向低位考虑该位能否为 \(0\)。枚举数位后校验,若从起点出发只经过该位为 \(0\) 的点能到达终点,这位就能填 \(0\)。
因为只关心当前点能否到达,不关心具体路径,所以只用记录目前能走到的最远点,来判断当前位置是否可到。如果可到,再用当前位置的信息更新能到达的最远点。
B
每个数操作后的值不超过原数组里的 \(maxx\)。要取到 \(maxx\) 就要出现 \(0\),产生 \(maxx-0\)。\(0\) 由两个相邻的数操作两次就能产生。
\(n \geq 4\) ,若 \(maxx\) 在除 \(2、n-1\) 的位置上存在,则可以全部变成 \(maxx\)。如果只在\(2\) 或 \(n-1\) 上存在,左或右边也可以被全部变成 \(maxx\),所以有另外的 \(maxx\) 来替代之前的。
\(n=3\) ,若 \(maxx\) 在两端,可以全部变成 \(maxx\) ;在中间,不能全部变,但可以全部变成 \(abs(a_1-a_2)\) 或 \(abs(a_2-a_3)\)。最后与不操作比较。
\(n=2\) 直接输出操作或不操作的较大值。
C
每次减去的总和都是偶数,如果原数总和是奇数一定无解;如果有比总和一半更大的数,就没办法消掉,无解。
先考虑 \(n=3\)。当 \(a_1+a_3=a_2\) 时,可以通过两次操作全变成 \(0\),即 \(a_1、a_1、0\) 后 \(0、a_3、a_3\)。否则先进行 \(w、0、w\) 操作,其中 \(w=(a_1+a_3-a_2)/2\)。\(a_1+a_3-a_2=sum-2*a_2\),\(sum\) 和 \(2*a_2\) 都是偶数,差也是偶数,所以 \(w\) 一定是整数。
最多三次操作。\(n\) 更大的时候,选连续的三段看作三个数。需要保证每段总和不超过总和一半,再按 \(n=3\) 做。
E
把偶数位的 \(0\) 变成 \(1\),\(1\) 变成 \(0\),问题变成可以删去 \(10、01\)。答案就是变换完 \(2\) 后 \(0\) 与 \(1\) 的个数差。
F
包含一个头或尾的矩阵,返回值是奇数,否则是偶数。按列按行查询,如果是奇数,再二分查找。遍历到最后一行或列,它的奇偶性可以直接确定,不需要查询。
G
二分答案。校验部分,一个数一定要加才去加,每次选包括这个数的区间里右端点最大的一个,注意一个区间只能用一次。区间加用差分实现,遍历一个点就算一个前缀和。前面已经满足条件,不会被后面影响。可以把原数组的数和区间的左端点一起排序,如果遍历到数字就处理,遍历到左端点就加一个区间。
-
2025/7/22
A,95 min,100(100)
先写了 \(n^2\) 暴力,然后想到每加进一个数 \(x\),可以算出以它作为结尾的路径产生的所有贡献。用单调栈维护,如果栈顶小于 \(x\) 就弹出。路径中 \(x\) 能接在被弹出的数后面,弹的同时累加答案。累加时要额外加若干个 \(1\),取决于有几种路径。所以再维护每个位置的路径数,弹的同时累加。
后面发现右端点不一定是终点,每个结尾可以往后延直到遇到比自己大的。要较快地知道右端第一个大于自己的数的位置。一开始不会写,1h 了补 30 分就跳了。后面发现用单调栈。
B,85 min,0(?)
想到对于 \(a\) 里连续一段相同的 \(x\),\(b\) 要找一些 \(x\) 匹配,跟一段后缀匹配就可以合法添加前面的 \(x\)。对于第一个数,如果 \(a\) 里面第一段的长度大于 \(b\) 里的肯定不行。所以去了个重然后枚举左端点,最终没写出来。
其实满足要求的区间 \(z\) 需要的条件首先是 \(b\) 是 \(z\) 的子序列,枚举左端点找到合法的 \(z\) 的最小右端点 \(r\),大于等于 \(r\) 的右端点都可行。还要满足第一个数必须相等,且 \(a\) 里第一个数段长度要小于等于 \(b\)。预处理每个左端点合法的最小右端点。
C,15 min,20(20)
D,45 min,50(50)
\(1\) 肯定都选,\(-1\) 看情况选。先正着按前缀和选一遍,再在选出来的序列基础上反着按后缀和选一遍。然后补了 \(1\) 和 \(-1\) 交替的 \(2\) 分。
-
2025/7/23
A
一定在最后的 \(0\) 处填最小值,填完当前最小值 \(i\),使它后面的 \(s\) 都减去 \(i\),再重复找最后的 \(0\) 填数的操作。找 \(0\) 过程由二分实现,线段树维护区间最小值。
B
对于当前降速后的车厢,会导致后面速度大于等于当前车厢速度的车头做不了车头。用 \(set\) 维护车头的下标,每次二分找在当前车厢后的第一个车厢,判断还能否做车头。降速后也可能使这个车厢变为车头,判断与前一个车厢的速度关系即可。
C
考虑 \(dp\),\(d_{i,0/1}\) 表示考虑到第 \(i\) 个位置,当前点是否被删除。单调栈求 \(i\) 之前最近的比 \(p_i\) 小的数的位置。注意取模。
E
线段树维护 \(a\) 最大值、\(b\) 最小值、\(a_i-b_j\) 最大值、\(-b_j+a_k\) 最大值、\(a_i-b_j+a_k\) 最大值。注意查询的时候也要算跨左右区间的情况。
-
2025/7/24
完成了上次的 D
建一个值域线段树,现存的数标 \(1\),题目要找第一段连续出现至少 \(k\) 个 \(0\) 的位置。维护连续 \(0\) 的最长段长度。注意所有数之前都没出现过,记得初始化。每个询问都重新建树太慢了,所以在一次询问结束后把还存在的数删掉,下次输入再加数。
-
2025/7/25
A,27 min,100(100)
正数只会跟正数乘,负数只会跟负数乘。预处理出 \(p_{i,1/0}\) 表示在 \(1\) 至 \(i\) 范围内区间和最大正数、最小负数,\(s_{i,1/0}\) 表示在 \(i\) 至 \(n\) 范围内区间和最大正数、最小负数。枚举分界,取正数相乘与负数相乘的较大值。
B,153 min,100(?)
正常情况过不了。考场上不知道怎么求每次加数后的个数前缀和,所以就暴力找了 \(w-1\) 个。
按 \(h\) 排序,枚举最大玩偶大小。更大的玩偶全部删掉,相同大小的 \(w\) 个全部保留,在更小的玩偶里保留 \(w-1\) 个价值尽可能大的。用两个线段树维护个数前缀和以及个数乘价值前缀和,二分找到 \(w-1\) 再查询。
C,30 min,0(25)
目前还不知道为什么第一档没有分。高度一定是先逐渐上升到最高点再逐渐下降,不存在折返的情况。并且从时刻上看高度变化应该是对称的,因为过程中高度越高越容易通过。所以可以看作从起点出发和从终点出发两条路在中间相遇。
所以从起点出发,要保证前段每个时刻都在上升,这样高度会尽可能高,所以当前所用时间就是当前高度。求从起点到达每个点的最小时间。从相邻的点转移来的时候,所用时刻要与自身高度取较大值,因为也许需要原地等上升到自身高度。可以用 \(Dijkstra\) 求最小时间。
从终点出发是对称的,也能求出从终点到每个点的最小时间。假设两条路在 \(u\) 点会合,\(x\) 表示起点到 \(u\) 的最小时间,\(y\) 表示终点到 \(u\) 的最小时间,总用时应该是 \(2*max(x,y)\),因为要同时满足达到每一边的高度。
不一定在点上相遇,如果中间需要平飞一格,总用时再加一。
D,30 min,25(35)
\(k=1\) 的情况有可能交集为空,忘记判了,少了 \(10\) 分。
-
2025/7/26
A
把长为 \(n\) 的原串复制两遍,能取到的长为 \(n\) 的子串就是能变换成的串,并且这些串之间通过一次变换可以互相转换。总共有 \(n\) 种变换方式。问题变成这 \(n\) 种串之间可以互相转化,问 \(k\) 次操作后有多少种方案能转成目标串。先求出能变换的串中有多少个目标串。考虑 \(dp\),\(d_{i,0/1}\) 表示操作 \(i\) 次后转换成目标串或非目标串的方案数。最终答案就是 \(d_{k,0}\)。
B
遇到能消的就先消,一定不劣。用栈维护 \(S\) 目前剩的字符的下标。\(KMP\) 过程中,每次把遍历到的下标加进栈里,如果匹配完了一个,就把匹配了的出栈,下次再从栈顶下标继续 \(KMP\)。
C
直接 \(KMP\) 会超时。当 \(i \leq n\) 时,只与 \(s\) 有关,所以可以先对 \(s\) 求 \(KMP\),再在每次询问时对 \(t\) 做 \(KMP\)。设 \(d_{i,j}\) 表示第 \(i\) 个前缀的所有 \(border\) 中最长的使得下一位是 \(j\) 的位置。
-
2025/7/27
A,140 min,60(60)
死活想不到写的容斥错在哪,然而长为 \(3\) 的交集的部分要加回来,因为被减完了,然后再减去 \(4\) 的。其实想到了,但是先去试别的方法给搞忘了。最后改两个符号就过。
B,50 min,100(?)
运气又好了。只能有一个或者两个非法段,因为一次操作只能变化两段。并且非法段长度要 \(<2k-1\),否则怎么分都会有一段长度 \(>k\)。反转区间的左右端点一定分别在不合法的段里。根据非法段个数分类讨论。
\(0\) 个,不需要操作就是合法状态。
\(2\) 个。如果两段字母不一样,可以通过一次操作达到合法,因为两段可以分成 \(<k\) 的四段,并且反转后不会融合。如果字母相同,因为两段总长度 \(\geq 2k-1\),一定有一段不合法,所以是 \(NO\)。
\(1\) 个。如果存在长度 \(>1\) 的不同于非法段字母的字母段,就可以。如果不存在,但存在一个与非法段加起来的长度 \(<2k-1\) 的相同字母段,也可以。
对两个字母相同的段操作,相当于总长度不变,看能否分配得两段都 \(<k\)。所以要满足总长 \(<2k-1\)。
C,30 min,0(10)
过于暴力了。最大化最小值想到二分。二分答案 \(x\)。把每种字母是否被填成长为 \(x\) 的连续段作为状态然后压成二进制。\(d_b\) 表示填了的状态是 \(b\),最少要用到多长的位置。每次枚举一个没填过的字母,然后连续往后填这个字母看要填到哪个位置。预处理每个位置填某个字母会到哪个位置。
D,20 min,15(15)
去想第一题了。
-
2025/7/28
A
\(d_{i,0/1/2}\) 表示涂完前 \(i\) 格,最后一格元素为 \(j\) 的最小代价。假设前面的都填完了,当前格可以花一个代价涂,也可以通过前面来涂。当前面一格的元素大于 \(0\),就可以通过前面涂。
还可能花一个代价涂完自己后,帮助前面的涂,当前点能顺着涂到向前的第一个 \(0\) 处,预处理出每个位置前的第一个 \(0\),再从 \(0\) 的前一位转移过来。
B
如果选出了一些杯子,肯定是尽可能把水倒进这些杯子。\(d_{i,j}\) 表示选了 \(i\) 个水杯,水杯容量之和为 \(j\),装的水的最大值。
-
2025/7/29
A
\(d_{i,j}\) 表示睡了前 \(i\) 次,时间为 \(j\) 的最大答案。因为每次都要 % \(h\),所以正在睡觉的 \(h\) 可以当作没有。注意第一次睡不能从小于 \(0\) 的时间转移过来,可以特判,也可以把 \(d\) 初始化成极小值,并且 \(d_{0,0}=0\)。
B
通过贪心预处理出 \(s_{i,j}\) 表示第 \(i\) 个矩阵获得 \(j\) 分的最小步数,再进行 \(dp\)。\(d_{i,j}\) 表示前 \(i\) 个矩阵,获得 \(j\) 分的最小步数。
C
先将列离散化。\(d_i\) 表示前 \(i\) 行最多选多少行,要在与这一行有交集的状态里找到最大的 \(d_j\) 转移过来。用线段树维护区间最大值,加入第 \(i\) 行时,求出与第 \(i\) 行有交集的最大 \(d_j\),转移后把第 \(i\) 行是 \(1\) 的位置更新成 \(d_i\)。
-
2025/7/30
A,40 min,100(100)
注意额外加的 \(d\) 每次加的都是一段前缀。
B,120 min,0(30)
有取模的问题。还要注意不止要考虑 \(maxa*maxb\) 以及 \(mina*minb\),\(mina*maxb\) 和 \(minb*maxa\) 也可以成为答案,比方说 \(a\) 或 \(b\) 全是正数,另一个全是负数。考试的时候也在 \(i\) 和 \(j\) 不一定需要 \(\&k=k\) 才能使得 \(i\&j \geq k\) 上出现了问题。
\(n\) 不超过 \(2^{18}\)。子集的转移,要么来自于它本身,要么把它的某一位改成 \(1\)。所以可以通过递推算出来子集后缀最大值和最小值。然后把 \(maxa\) 等两两之间相乘取最大,最后算一遍后缀和。
C,20 min,9(24)
第二档猜错了。
D,40 min,8(8)
写了一档搜索。
-
2025/7/31
A
按题目模拟一遍二分,\(mid\) 在 \(pos\) 左边,就要填 \(\leq x\) 的数,在右边则填 \(\geq x\) 的数。除了这些位置,其他位置随便填。
记录一下需要 \(cnt1\) 个 \(\leq x\) 的,\(cnt2\) 个 \(\geq x\) 的。在所有 \(\leq x\) 的数里选 \(cnt1\) 个进行排列,在所有 \(\geq x\) 的数里选 \(cnt2\) 个进行排列,剩下的 \(n-cnt1-cnt2\) 个随便排。答案由各部分相乘。
B
把 \(n\) 尽量往前面排。如果有一组 \(p、q\) 是 \(n、n\),就把它放在第一个,第一问答案为 \(2\);如果没有,且 \(a、b\) 两组分别有一个 \(n\),就分别放在第一第二个,答案为 \(3\)。
对于第一种情况,两个 \(n\) 在开头,后面怎么排都不影响第一问答案,所以第二问是 \((n-1)!\)。第二种情况,假设 \(a\) 在第一个,则不能在 \(a、b\) 之间放大于 \(a\) 的组,可以枚举 \(b\) 放在 \(i\) 处,在比 \(a\) 小的组里挑 \(i-2\) 个排列在 \(a、b\) 中间,剩下的随便放。\(b\) 放第一个计算方式一样。
C
上方左方一共操作了几次,当前位置也需要这么多次操作才能把加的 \(1\) 减掉,所以操作次数的数组 \(z\) 类似于杨辉三角,\(z_{i,j}=z_{i-1,j}+z_{i,j-1}\)。
杨辉三角中,第 \(i\) 行第 \(j\) 列的数字等于 \(C^{j-1}_{i-1}\)。发现 \(z_{x,y}\) 对应到杨辉三角上,有 \(x+y-1=i,y=j\) 的关系,所以 \(z_{x,y} = C^{j-1}_{i-1} = C^{y-1}_{x+y-2}\)。
要对所有 \(z\) 求和。一系列简化后等于 \(\sum_{i=1}^{n+1} C^{a_i-1}_{a_i+i-1}\)。
D
反着考虑,答案由总方案数减去不合法方案数得到。
计算总方案数,枚举添加的总长度 \(k\),把它分配给三根棍子,允许有棍子不被分配。相当于在 \(k+2\) 个位置选两个位置做隔板,也就是 \(C^{2}_{k+2}\)。
计算不合法方案数,添加完之后最长边要大于另两边的和。枚举最长边是哪个,假设是 \(a\),再枚举最长边添加 \(x\),为了不合法,还能给另两根添加一共 \(len=min(l-x,a+x-b-c)\) 长度。也相当于把 \(len\) 分成三份,允许有空的,第三份不放在任何一根上,起到控制添加的总长度可以不同的作用。

浙公网安备 33010602011771号