做题集合
T1.P10136
神秘人类智慧题。
如果离散化后的 \(n \le 3\),那么答案即为 \(\dfrac{mx \times (mx + 1)}{2}\)。接下来考虑 \(n \ge 4\) 的情况。
应为鸽巢原理当 \(a_i \bmod L\) 只有三种不同的取值,所以必定有两个数 \(i,j\) 满足条件 \(a_i \equiv a_j \pmod L\) 并且 \(1 \le i < j \le 4\)。那么就可以推出 \(L \mid (a_i-a_j)\)。
那么我们只需要枚举所有满足条件 \(1 \le i < j \le 4\) 的 \(i,j\),然后查看 \(a_i - a_j\) 的所有因数当中所有符合条件的数的和即可。
T2.P4156
我们先求出所有 \(|s| - \text{border}\) 的长度,记为 \(\{x_i\}\),那么题目要求的就是 \(\sum^{cnt}_{i = 1} a_i \times x_i\) 能在 \([0,w - |s|]\) 中取到多少种值。
注意到这个形式是同余最短路的形式,所以我们考虑使用同余最短路来解决。但是直接做是 \(\mathrm O(n^2 \log n)\) 的,不可以通过。
此时抛出一个定理:一个字符串排序之后,必定有一种划分序列的方式,使得所有的序列均为等差序列,且序列个数为 \(\mathrm O( \log |s|)\)。
那么根据 \(\text{border}\) 这个优美的性质,我们考虑把 \(x,x + d,x + 2d \cdots \cdots x + l \times d\) 这个等差数列在 \(\bmod x\) 的意义下跑同余最短路。其中 \(y\) 连向 \((y + d) \bmod x\)。那么会形成 \(\gcd(x,d)\) 个环,每一个环分开处理。
我们发现一个环中 \(dis\) 最小的点是不会更新的。并且两边的点的 \(dis\) 均等于 \(d\)。那么我们就从这个点出发用单调队列结算 \(dis\)。我们在单调队列里放入离现在处理点距离小于等于 \(l\) 的点,以 \(dis_i - pos_i \times d\) 作为比较,这样我们就能处理环上的转移。
那么剩下的为题就是怎么两个不模数的转移。假设现在的模数为 \(now\),之前的为 \(lst\),那么很明显 \(dis_i\) 可以更新 \(dis^{'}_{dis_i \bmod now}\)。然后根据定义我们只需要在 \(\bmod now\) 的意义下跑一遍同余最短路并且使用用 \(x\) 更新 \((x + lst) \bmod now\) 即可。
时间复杂度为 \(\mathrm O(n \log n)\)。
T3.P9197
考虑连续段 dp。
我们把 \(a_i\) 从大到小后排序然后依次插入。
此时我们设计 \(dp_{i,j,k,s}\) 表示目前考虑了 \(i\) 个数。有 \(j\) 个连续段,目前答案为 \(k\),首尾都没取/只取了其中之一/两个都取了。答案就是 \(\sum^l_{i = 0}dp_{n,1,i,2}\)。
转移就很简单了:
-
作为首尾,开新段:相邻一个数,但是没有填,价值为 \(A_i\)。
-
作为首尾,接着另一个段:相邻与个数,填了,价值为 \(-A_i\)。
-
不作为首尾,开新段:相邻两个数,但是都没有填,价值为 \(2 \times A_i\)。
-
不作为首尾,连接两个段:相邻两个数,都填了,价值为 \(-2 \times A_i\)。
-
作为首尾,接在一个段的后面:相邻两个数,一个没有填,一个填了,价值为 \(0\)。
然后直接转移即可。
T4.AT_agc001_e
首先我们知道 \(\dbinom{a_i+b_i+a_j+b_j}{a_i+a_j}\) 等价于从 \((0,0)\) 到点 \((a_i + b_i,a_j + b_j)\) 的方案数。
但是这样子还是不能解决,应为我们还是要枚举终点才能知道。
此时我们考虑变为从 \((-a_i,-b_i)\) 到 \((a_j,b_j)\) 的路径数量。
那么这样就只会有 \(n\) 个起点和 \(n\) 个终点。
此时我们定义 \(dp_{i,j}\) 表示丛所有的起点走,有多少种路径可以到达 \((i,j)\)。
那么答案即为 \(\dfrac{\sum_{i=1}^n{dp_{a_i,b_i}} - \sum_{i=1}^{\dbinom{2\times(a_i+b_i)}{2\times a_i}}}{2}\)。
当然为了防止负数溢出,所有的坐标 \((x,y)\) 都变为 \((x+2000,y+2000)\)。
T5.AT_agc043_d
好玩的。
假如这个序列为 \(\{3,2,1\}\) 状物,那么当第一个数被选出后,后面两个数立刻会被选出。
这样我们可以把下降的一段用第一个数字代替。这样这个操作就是正常的排序了。
那么一个长度为 \(3\) 的序列就可能贡献:
-
一个长度为 \(3\) 的下降子序列。
-
一个长度为 \(2\) 和一个长度为 \(1\) 的下降子序列。
-
三个长度为 \(1\) 的下降子序列。
那么我们此时设计 dp,其中 \(dp_{i,j}\) 表示目前考虑到第 \(i\) 个数,长度为 \(1\) 的字段数量比长度为 \(2\) 的字段数量多 \(j\)。然后转移 dp 即可。
T6.AT_arc070_c
Slope Trick!
先有个朴素的 dp:我们定义 \(dp_{i,j}\) 表示把第 \(i\) 个方块移到 \(j\) 这个位置上的最小代价。那么转移方程就是:
然后因为 \(|j - l_i|\) 为凸函数,然后我们发现 \(dp_{i,*}\) 为凸函数。然后我们考虑用队列来维护这个凸包的每一个转折点。
具体的,我们维护斜率大于 \(0\) 和斜率小于 \(0\) 的部分的转折点,同时答案必定会在斜率等于 \(0\) 时取到。
T7.神秘
我们考虑定义 \(dp_i\) 表示前 \(i\) 个数能表示出的不同序列的数量。
那么就有:
其中 \(g_{i,j}\) 表示区间 \([j,i]\) 能表示出区间 \([j,i - 1]\) 有多少个不能表示出的序列。
假若我们可以将 \(a_i\) 插入 \([j,i - 1]\) 的线性基当中,那么 \(g_{i,j} = 2^p\),否则为 \(0\),其中 \(p\) 为线性基的大小。
T8.AT_abc236_f
基本不会线性基了,做几道练练手。
既然要代价最小,那么先将代价从小到大排序。排完序后,我们将下标插入线性基,如果可以插入,那么就加上这个下标对应的代价,否则跳过。
T9.神秘2
我们发现如果维护每一个点肯定是不现实的。
但是我们发现同一层的点的情况是相同的。一就是说一个点跟深度有关,和位置无关。然后我们发现有区间操作,于是考虑用线段树来维护。
然后我们发现一个点 \(x\) 肯定是先向祖先走若干步,然后再儿子走若干步。那么我们就可以维护这个点向祖先走的步数,以及向儿子走的步数与方向,然后再把两条路径合并即可。
T10. P7470 [NOI Online 2021 提高组] 岛屿探险
我们可以发现这个东西可以拆成很多个子问题,然后累计合并,这个东西可以使用线段树合并来做。
先考虑 \(b_i > d_j\) 的情况。那么答案就是 \(\sum [a_i \oplus c_j \le d_j]\)。我们把 \(a_i\) 插入 \(01 \text{trie}\) 中。然后我们从上往下走,走到深度为 \(h\) 的节点,那么代表他的值等于 \(c_i \oplus d_j\) 的前 \(h\) 位。然后我们考虑第 \(h + 1\) 位。
-
\(d_i = 0\),那么 \(a_i\) 和 \(c_j\) 的第 \(h + 1\) 位必须相等,否则 \(a_i \oplus c_j > d_j\),然后直接往这个方向走即可。
-
\(d_i = 1\),那么此时 \(a_i\) 和 \(c_j\) 的第 \(h + 1\) 位任意取都行。那么就有两种可能:
- 如果 \(a_i\) 和 \(c_j\) 的第 \(h + 1\) 位不一样,那么此时 \(a_i\) 依然等于 \(c_j \oplus d_j\),所以我们向这个方向继续走即可。
- 如果 \(a_i\) 和 \(c_j\) 的第 \(h + 1\) 位一样,那么此时 \(a_i \oplus c_j\) 就会一定小于 \(d_j\) 了,那么对于答案的贡献就是这个子树里 \(a_i\) 的个数之和。
这一部分就是 CF817E。比较简单。
接下来我们考虑 \(b_i \le d_j\) 的情况。这一个部分比较困难。但是我们发现这一个部分和 \(a_i \oplus c_j \le d_j\) 的结构很像,所以我们可以考虑类似的操作。
前面的是对于 \(a_i\) 扔到 \(01 \text{trie}\) 上然后查询 \((c_j,d_j)\),那么我们这次就可以把 \(c_j\) 扔到 \(01 \text{trie}\) 上,然后记录每一个 \((a_i,b_i)\) 对于 \(c_j\) 的贡献。
具体的我们只需要把 \(c_j\) 离线下来,然后对于 \((a_i,b_i)\) 查询,但是唯一的区别就是在上面我们遇到了一个节点满足 \(a_i \oplus c_j < d_j\) 时我们加上的是子树里 \(a_i\) 的个数和,而现在我们要在这一个子树打一个标记,让整一个子树全部都加上 \(1\),然后统计答案是就是从根到 \(c_j\) 路径上的标记和。
当然我们不能每一次都建 \(2\) 个 \(01 \text{trie}\),但是那样子的复杂度爆炸,无法接受。
然后我们考虑如何优雅的计算多组数据。
首先我们将 \((a_i,b_i)\) 和 \((c_j,d_j)\) 按照 \(b_i,d_j\) 升序排列。然后那双指针进行维护。此时我们开两个 \(01 \text{trie}\)。然后当我们扫到了第 \(j\) 个问题不满足 \(b_j > d_j\) 的 \(a_i\) 从维护第一个 \(01 \text{trie}\) 中删除,然后计算贡献。同时对于满足条件的 \((a_i,b_i)\) 加入维护第二个情况的 \(01 \text{trie}\) 上并且计算贡献。
当然此时两个指针都往右移动。
T11.The Third Grace
*3200。首先你需要知道 KTT,不会的话请做 P5693。
考虑 dp。我们定义 \(dp_i\) 为我们最后一个激活的点为 \(i\) 的最大权值,但是其中不包括 \(i\) 的贡献。
应为我们不会算当前点的贡献,所以我们可以增加一个虚点 \(m + 1\),那么答案就是 \(dp_{m + 1}\)。
然后我们考虑如何转移。
我们枚举下一个激活的点的位置。因为我们现在加的是 \(i\) 对于答案的贡献,那么 \(dp_j = \max(dp_j,dp_i + \sum_{l = 1}^n \sum_{r = 1}^n [l \le i \le r < j] \times p_i)\)。
然后扫描线一下,对于所有的 \(x\) 维护所有 \(y\) 的贡献,最后取 \(\max\) 即可。
接着我们发现贡献的式子是一个一次函数 \(y_i = k_i x_i + b_i\)。那么我们需要维护三种操作:
-
全局求 \(\max(y_i)\)。
-
对于一个区间 \([l,r]\),让里面的所有 \(x_i\) 都加上 \(1\)。
-
单点修改 \(b_i\)。
我们用 KTT 来维护这些一次函数,时间复杂度为 \(\mathrm O(m \log^3 m)\)。
T12.P10120
老大过得还好吗?
我们定义 \(A_i\) 为最后连续喝了多少瓶原味冰红茶,\(B_i\) 为最后连续喝了多少瓶热带风味冰红茶。
然后我们就发现第一个操作就等价于:
\(\forall i \in [l,r] A_i \to A_i + k,B_i \to 0\)
\(\forall i \in [1,l - 1] A_i \to 0,B_i \to B_i + k\)
\(\forall i \in [r + 1,n] A_i \to 0,B_i \to B_i + k\)
那么对于这个操作,我们只需要维护一颗线段树,支持区间推平和区间加即可。
接下来考虑第二个操作,我们考虑到哪一种节点就不用往下搜了。
这是简单的:只要这个子树里面 \(\max A_i\) 和 \(\max B_i\) 都小于 \(k\) 即可。
剩下的就正常做即可。
T13.AT_agc023_f
应为删点不好做,所以我们套路的变为合并。那么这题就变为:最初有 \(n\) 个孤立点,然后每一次和他的父亲合并。那么在合并的过程中,同一个连通块内部的最少贡献是不变的。我们所要做的事情是合理地安排它们的顺序,使不同连通块之间的产生贡献最小。
假设点 \(u\) 所在的集合中,\(0\) 点的数量为 \(cnt_{u,0}\),\(1\) 点的数量为 \(cnt_{u,1}\),点 \(v\) 同类。那么 \(u\) 排在 \(v\) 前面,跨越联通块的贡献为 \(cnt_{u,1} \times cnt_{v,0}\)。那么我们把 \(u\) 放在 \(v\) 前面更优的方案的判定就是 \(cnt_{u,1} \times cnt_{v,0} < cnt_{u,0} \times cnt_{v,1}\)。
所以我们按照 \(\dfrac{cnt_{u,1}}{cnt_{u,0}}\) 的大小来排序即可。
T14.AT_yahoo_procon2019_qual_e
好玩的题目。
先考虑最普通的题目。
给定 \(n\) 个数,问你有多少个子集满足异或和为 \(0\)。
这个题的解法很简单,就是建出一个线性基,那么答案就是 \(2^{n-\text{线性基内元素个数}}\)。
\(0\) 可以换成任意数,前提是可以被异或出来。
对于本题目我们先从选择若干行下手。答案只可能和每一列分别异或起来有关。
那么我们看异或后的结果。因为异或完也只有 \(0,1\) 两种可能,所以线性基的大小肯定是 \(1\)。那么看 \(1\) 能否被线性基表示,即为这个线性基里面是 \(0\) 还是 \(1\)。
然后你发现如果这个是 \(0\),那么这一堆均为 \(0\),否则就有 \(2^{m-1}\) 种情况。
那么这样子我们就可以把这一行看成一个 \(m\) 为的二进制数。那么我们就可以把这几个数插入到线性基中。
那么答案即为 \((2^n-2^{线性基内元素个数}) \times 2^{m-1}\)。
T15.CF1936B
有趣的题目。
先考虑 \(i\) 位置的小球会在哪一个边出。很明显,如果 \(\sum^i_{j = 1} [s_j == >]\) 大于 \(\sum^n_{j = i + 1} [s_j == <]\) 那么就会从右边出去,反之从左边出。此时我们考虑最优答案怎么算。
在此我们以 \(s_i\) 为 <,并且最后从做左出的情况为例,而其余的情况相同。
我们记 \(l_k\) 为 \(i\) 左侧第 \(k\) 个满足条件 \(1 \le j \le i\) 并且 \(s_j == >\) 的 \(j\),\(r_k\) 同理。很明显,我们的路线应该是先走到 \(l_1\),然后走到 \(r_1\),然后再走到 \(l_2\),然后再走到 \(r_2\),这样子一直走下去。
那么总路程就是 \(|i - l_1| + |l_1 - r_1| + |r_1 - l_2| + \cdots \cdots + r_cnt = 2 \times \sum^cnt_{i = 1}r_i - 2\times \sum^cnt_{i = 1}l_i + i\)。
\(cnt\) 的求法是平凡的,我们只需要用前缀和即可。
T16.P9200
考虑暴力枚举 \(n + 1\) 在哪一个位置后面,然后每一次考虑维护答案。
此时我们记 \(sum_i = \sum^i_{j = 1} e_j\)。那么对于从一个起点 \(i\) 移动到终点 \(j\) 的电荷量就是 \(sum_j - sum_{i - 1}\)。
那么我们要求的答案就是 \(\sum^{n + 1}_{j = 1} |sum_j - sum_{i - 1}| \times c_j\)。其中 \(i\) 为粒子环游的开始节点。由于 \(sum_{n + 1} = sum_{0} = 0\),所以这个式子就等价于 \(\sum^{n + 1}_{j = 1} |sum_j - sum_i| \times c_j\)。那么现在我们考虑这个式子在什么时候取到最最小值。
但是我们发现直接处理绝对值是一件很难的事情,所以我们考虑用几何意义吧绝对值拆开来。那么上面那个式子的几何意义就是在数轴上有 \(n + 1\) 个点,点有点权,现在需要选取一个点,使得所有点到这个中心点的加权距离和最小。但是我们发现带权也不好做,所以考虑把一个点拆成 \(c_i\) 个点,那么总点数就变为了 \(\sum c_i\),并且不带权。
那么我们只需要选出来这 \(\sum c_i\) 个点的中心点就行了。即点按照坐标大小排序后的第 \(\lceil \dfrac{\sum c_i}{2} \rceil\) 个数,然后这个东西用权值线段树维护即可。