正睿模拟赛题目记录
ZROI 寒假1 A. 念念不忘
可以发现一个有 \(x\) 个点的 \(f_i\),增加一个点的代价为 \(2(x+1)f_i\),删去一个点的代价为 \((2x-1)f_i\)。
全局贪心
全局整体考虑,我们可以转化一下思路,不一定是从子节点往上移动。可以变成从无到有的放置棋子,只需要满足子树总和小于子树大小即可。
我们对于每一个点,将从目前状态放置一枚棋子的代价放入堆中,每次选取代价最小的点放置。同时给上方的链上所有点允许放置的个数集体减 \(1\)。
查群该点如果还能放的话,就算一下下次添加的代价,放入堆中。可以用树链剖分维护,时间复杂度 \(O(n\log^2n)\)。
子树贪心
赛时想到了将目前代价最大的节点往上放最近的可以放的,树剖维护。感觉复杂度要爆,而且难实现,正解很接近,思路有点像。我们不要零散往上放,而是从子树合并上来的时候一起决策放。
如果一个节点放了多个点,为了方便写,可以拆开成多个大代价的点插入好写点。按照上面所说的增减代价放。
复杂度看似极限情况下不对,但实际上是对的。比如我们决策 \(u\),肯定是将 \(u\) 子节点的中权值最大的一些替换为 \(u\) 中最小的一些。将 \(u\) 升序排列,\(v\) 降序排列。假设替换了 \(p\) 次,那么根据等差数列公差 \(u_{p+1}>2u_{p/2}\),\(v_{1,2,..p}<v_{p+1}\),\(u_{p+1}>v_{p+1}\),可得 \(v_{1,2..p}\) 都变成了小于自己一半的数。那么一个数最多也就会变化 \(\log\) 次,故复杂度正确。
闵可夫斯基和
树上背包 dp,考虑 \(dp_{i,j}\) 表示 \(i\) 子树放了 \(j\) 个点,我们发现这是凸的。也就是 \(dp_{i,j}-dp_{i,j-1}\) 递增,我们可以用启发式合并差分,取最小的差分即可。原理是如果差分不递增的话,我们优先选小的差分会造成某个子节点的第一差分没选,选了第二差分。这显然是不行的,因为我们发现如果要选一段差分,必须从头选,只有最小化且差分递增的时候才能用。
模拟费用流。
ZROI 寒假1 B. 罗生门
不要被题目形式所迷糊,冷静分析一下,或者写个程序输出一下发现是 \(a_i\) 行 \(i\) 的二进制表示拼接在一起。如果是 \(n \times n\) 的积和式的话状压是可以解决的,但是这个做法在本题没有前途。
同样可以考虑容斥,式子为 \(\sum\limits_{s}(-1)^{\lvert s\rvert}\sum\limits_{i}\prod\limits_{j\notin}A_{i,j}\)
在本题做法也是容斥原理,\(\sum\limits_{s}(-1)^{n-\lvert s\rvert}\sum\limits_{选 n 行} \prod\limits_{j \in s}A_{i,j}\)。对于每一行如果对应的二进制数为 \(T\),那一行可能产生权值的位置个数为 \(\lvert T~and~S\rvert\)。设可能位置个数为 \(i\) 的出现了 \(c_i\) 次。那么给定 \(S\) 如何求 \(\sum\limits_{T_i\operatorname{and} S}a_i\)。我们设 \(dp_{i,j,s}\) 表示考虑了 \([0,i-1]\) 位,当前有 \(j\) 个 \(1\),\(s\) 是由 $[i,n] $ 为原数,\([1,i-1]\) 位为和 \(S\) 按位与之后的结果,的 \(\sum a\)。初始值是 \(dp_{0,0,s}=a_s\),每次不断缩短 \(s\) 即可。
某一行每一行可以选择的有 \(i\) 个,乘法原理即可。注意这个容斥的时候由于一共有 \(n\) 行我们却只选了某些列,所以允许列重复出现。用生成函数解决一下就是
直接生成函数部分二项式定理计算为 \(O(2^nn^3)\),其中容斥是 \(O(2^n)\),计算是 \(O(n^3)\)。
通过先取 ln 再反过来 exp 可以做到 \(O(2^nn^2)\) 来计算。
ZROI 寒假1 C. 雷克雅未克
我们发现一个极大正方形肯定是被至少三个点卡住。可以发现每个点会扩展出 \(O(1)\) 个极大正方形,于是总共有 \(O(n)\) 个极大正方形。
如果我们对于 \(y\) 轴建立可持久化线段树,然后对于每个点二分一个 \(l\),在可持久化线段树的 \([y,y+l-1]\) 区间内寻找 \(x\) 的前后驱记为 \(x_1\) 和 \(x_2\),然后直到找到 \(x_2-x_1=l\)。如果找不到说明不存在或者有一个卡着上界左右只存在一个点。这是 \(2\log\) 的,如果我们左边扫一下,右边扫一下再在两颗线段树上同时二分是 \(1\log\) 的。
然后就是对于每个询问点和矩形的匹配了,如果传统套路线段树上节点放 set 是 \(2\log\) 的,发现如果一个矩形比另一个小还更早消失,那么是不优的。我们可以通过节点上维护单调队列来完成这个操作,复杂度也是 \(1\log\) 的。总的时间复杂度 \(O(n\log n)\)。
注意要通过设置无限远的点来制造无限大的矩形,从而判断无解。
ZROI 寒假2. A.千年红
结论:dfs 走出的树上全是返祖边,bfs 走出的树上全是横叉边。
当 \(n,m\) 比较小的时候,可以直接 dfs 构造出来一组全是返祖边的树,然后一条边一条边的调整。
但是可以更快,我们发现如果 \(u\) 有 \(k\) 个祖先边 \(e_1~e_2~e_3...e_k\) 本来是连着 \(e_1\),如果调整到 \(e_{t+1}\) 的话,就会少 \(t\) 条返祖边。于是我们可以正好凑出 \(a\) 条返祖边,然后 bfs。或者直接对于每个点记录所有祖先边,对 dfn 排序,然后从根最后遍历一遍调整。
记录下所有祖先边再最后上调这步是关键。
ZROI 寒假2 B.秋海棠
在值域不不大的时候,线段树二分是显然的。
值域过大的时候其实并不是找规律,这种东西都随便给的询问也很难找规律维护,也还是是线段树二分,但是需要动态开点就行。
线段树一大重点就是维护信息。现在考虑如何快速修改,直接对于每个节点打上标记 \((x,y)\) 表示下标 \(\bmod 2^x=y\) 的位置保留,假如新传入标记 \((1,1)\),原先的保留下来的是 \(2^xk+y\),注意区间剩余位置奇偶性只和 \(k\) 有关,和 \(y\) 无关。现在就是 \(2^x(2k+1)+y=2^{x+1}k+y+2^x\),对应修改即可。
附带剪枝,防止 \(x\) 过大,当区间个数为 \(0\) 的时候我们不改变 \(x\),当区间个数为 \(1\) 的时候,新标记保留首个元素,不改变 \(x\),这样子 \(x<2^{60}\)。
ZROI 寒假2 C.六月雪
对于 \(0 1\) 作 \(+- 1\) 前缀和,发现对于一个和为 \(k\) 的段可以拆成 \(k\) 个权值为 \(1\) 的段是更优的。我们考虑限制一下段的权值之和 \(\le 1\)。
非正的区间我们设其和 \(sum_0\),那么正的段总和为 \(sum_1=sum-sum_0\),为了最大化 \(sum_1\),我们就要最小化 \(sum_0\),也就是现在要划分 \(i\) 段非正,使得其总和最小。假设求出来选 \(i\) 段和最小为 \(f(i)\),那么答案就是 \(\max\limits_{i=1}^k\{\min(sum-f(i),k-i)\}\)。
现在的问题就变成选 \(k\) 个区间和最小。想一想这种非连续的东西是不太好在 \(O(n\log n)\) 的时间内直接 DP 的,可以用分治。我们设 \(dp_{l,r,cnt,0/1,0/1}\) 表示在区间 \([l,r]\) 中选了 \(cnt\) 个区间权值和最小,0/1 表示左右端点是否闭合。可以发现 DP 是凸的,于是我们直接闵可夫斯基和,也就是对于 \(cnt\) 的 \((\min,+)\) 卷积。这样子时间复杂度就是 \(O(qn\log n)\) 的。
发现上述分治比较像线段树结构,于是我们可以把询问放在线段树上。
ZROI 寒假4 A. Graph
对于第一类操作小于等于 \(10\) 时,可以看作绝大部分操作都是复制原先的点的周围连边,只有极少部分是新改变一些图。
继承上面的思路,对于全部数据直接维护时很难的,我们考虑对于每次给出的两个点 \((u,n+1)\) 之间连边,边的类型的是操作类型,这样子 \(2\) 边配合上时间序也可以很好刻画边的复制情况。生成的是一棵树,而且因为每个点只会在加进来的时候向上连边,所以树上操作时间序就是从上到下的。
发现当 \(w\) 和 \(p\) 之间先连了一条 \(1\) 边,然后 \(w\) 和 \(p\) 下面后挂了一堆 \(2\) 边,那么这些 \(2\) 边可以通过传导使得 \(w\) 和 \(p\) 下面的两条链联通。
考虑加入点 \(v\),维护其对于 \(u\) 的贡献,根据 \(1\) 边出现位置的不同有两种贡献。
-
找到 \(v\) 祖先中的第一个 \(1\) 边,对于该祖先连着的所有后加入的 \(2\) 边以及其子树进行区间加。
-
找到 \(u\) 祖先中第一个 \(2\) 边,对于该祖先先加入的 \(1\) 边下属进行求和。
两个树状数组即可。
具体实现方法就是对于每一个以 \(1\) 类边为割边的联通块进行 dfn 编号,同时记录最上面的点,这样子的话可以让 \(1\) 边和 \(2\) 边互不干扰。
ZROI 寒假4 B. Prefix Sum
一定要小心计数问题不能算重,如果直接设 \(dp_{i,j,k}\),其中 \(k=\sum a_i-\sum b_j\),必然会算重,因为 \(i~j\) 的转移顺序没确定,而且时间复杂度也超了。
故考虑钦定转移顺序,我们在 \(k<0\) 的时候选 \(a\) 直到大于 \(0\),在 \(k>0\) 的时候选 \(b\) 直到 \(k<0\)。这样不仅不会让转移算重而且限定了 \(k \in [-V,V]\),保证了时间复杂度。
ZROI 寒假4 C. Shortest Path
\(c=1\) 的时候一个很显然的想法就是边权为整数,次短路必然至少打大 \(1\)。所以只需要把最短路调整好就可以了,经典套路我们建立最短路图然后对着这个图操作即可。下面的操作也就是选最少的边使得 \(1\) 到 \(n\) 的每一条路径上都包含至少一条选择边。其实就是用选择边断开 \(1\) 到 \(n\),我们只需要最小割一下即可。
考虑扩展一下,原问题能不能最小割。其实是可以的,直接把边权设置为 \(c-(d_u+w-d_v)\) 就可以了。那最后的情况应该是选择若干边直接搞为很大,并不是选很多条边每一条边变大一点,因为专注于一条边变大显然是更好,这样可以以小代价影响到更多路径。
还一种方法,考虑将原问题转化为线性规划,然后对偶一下,最后费用流。利用费用流结论流量只有可能是整数,将实数流量变成整数。
ZROI 暑假1.A好吃
tarjan 缩点,DP背包一下就行了。
ZROI 暑假1.B呼啸浪潮
\(C\) 的回文串直接用 Manacher 即可。
发现能出现形如 BB 的形式,需要 \(\operatorname{lcp}(i,j)\ge j-i\) 然后对于 \(BB\) 我们可以用 SA 求出 height 数组。然后按照最小值笛卡尔树,\(\operatorname{lcp}\) 就是 LCA,我们每次找树比较小的部分枚举,另一部分二维数点,这是 \(2\log\) 的。
单 \(\log\) 做法见 NOI2016优秀的拆分。
ZROI 暑假1.C无禅零区
可以发现图是由若干个联通块构成,联通
定义合法有根树是能区分根和其他点,并满足子树均合法,且子树不能一样。我们可以从点数从小到大枚举所有合法有根数。可以把所有点放进优先队列,每次取出最小的。
ZROI 暑假2.A排序
可以把一个数组分成三段,然后三段归并排序。只用了三个里面取最小值的信息。
为了利用最大值,我们可以用四路归并。时间复杂度 \(T(n)=4T(\dfrac{n}{4})+n-1\),也就是 \(O(n\log_4n)\)。
还可以改变快排,快排是找到一个数 \(x\),然后找所有数,比他小就放左边,比他大就放右边。于是每次比较中间和其他两个,但是这样子可能会不平衡,我们可以随机 \(\log\) 个找到比较靠中间的作为中点。
ZROI 暑假2.B节日庆典
ZROI 暑假2.C求和
发现 \(\sum f(i\times 2^{m-1})\) 是很多个 \(2^{m-1}\) 的倍数的 \(f\) 值求和。
ZROI 暑假3.A
暴力询问点对 \(O(n^2)\)。
对于二分图,我们因为某一部分内部无边,我们可以二分一下,对于左边每个点找到右边第一个和他有边的点,然后以此类推找到下一个和再下一个。注意写法问题,如果是找到按照上面讲的写法的话是 \(\log n+1\) 次,但是如果分治解决,每次看左右儿子有没有的话,会被卡成 $2\log $ 的,因为如果我们每个左边点水平连向右边点的话每层都会左右一下。
对于特殊性质 \(B\),可以将连边看成不等号,那么没连边的都是相等的,于是这个图就是一个完全 \(k\) 部图,也就是每一个部内部无边,但是不同部的所有点之间都有边。我们可以依然不同部,然后类似二分图那样子二分一下。
正解就是把所有没有边的放在一个部里,然后部之间二分一下即可。
ZROI 暑假3.B
ZROI 暑假3.C
\(\operatorname{Xor-MST}\) 是很经典的题目,如果
ZROI 暑假4.A
暴力方程 \(dp_{i,j}=\min(dp_{i-1,j}+w_{up},dp_{i,j-1}+w_{right})\)。
对于这种整个整个往上转移的,而有明显的分段特征的,这里的段就是激光的起点在每一行的作为分界点,分界点之间的 \(w\) 不变。可以考虑线段树维护整体 DP。发现行内转移不太好处理,我们要利用同一段中 \(w\) 相同,可以维护 \(dp_{i,j}+w_r(j,n)\),这样子行内影响就消除了,每一个位置的值就等价于前缀最小值。我们只需要处理行间转移以及 \(w_{up}\) 即可,发现 \(w_{up}\) 的值仅在水平激光端点处变化,我们找到端点后所有端点后的值如果是从上一行转移的应该整体 \(+1\)。怎么找到从上一行转移的位置呢,根据前面前缀最小值的性质,我们发现从一个出发应该是一段 \(x,x,x....x,<x,<x\),这个样子 \(<x\) 的位置必然不是通过前缀最小值得到的,于是我们只需要找到第一个小于 \(x\) 的位置,然后给那段后缀整体 \(+1\)。
解法二是发现这个 DP 转移式子很有差分的感觉,而且行内具有单调性,于是考虑维护差分。首先行内转移的式子规定了差分的上界是 \(w_{right}\)。然后可以通过行间转移来使得差分更小,大概就是从小到上会有一个 \(w_{up}\),然后可以用他加上上一行的 \(\delta'\) 来更新这一行 \(\delta\) (初始值是上界 \(w_{right}\))。模拟从下往上合并的过程,其实如果我们是从小往上合并的话,那么初始值应该是上一行的 \(\delta'\),然后和 \(w_{right}\) 也就是上界取 \(\min\),如果是前者小,那么不会发生变化,如果是后者小那就更新 \(\delta\),同时由于这个地方的值变了,那么会影响下一个 \(\delta_{next}\),具体来说下一个值应该会变大。模型化,就是那个点有一个容量上界,我们可以往点里面加球,如果球多于上界,就会一直往右传递,一直转移到最后一行每个位置里的球数就是最后的差分数组。每个位置的容量就等于上一行该位置的容量加上新增的向上的激光。
ZROI 暑假4.B
\(E((x+y)^n)=\sum\limits_{i=0}^n {n\choose i} E(x^i)E(y^{n-i})\)
ZROI 暑假4.C
一个贪心的想法就是每个点每次都走到所在区间内的最远点。
考虑如果维护一个点能走到的最远点,我们对于一个加入操作 \((l,r)\),我们可以对于每个 \(i\in [l,r]\) 的 set 中加入 \(r\),每次询问暴力跳即可,这是暴力做法。这个过程其实也可以用分块维护,对于整块维护 set,块内
特殊性质 \(A\),直接树状数组维护区间和即可。
特殊性质 \(B\),发现跳跃关心呈树形结构,我们从左端点向右边能到最远点连一条 \(1\) 的边,向左边一个点连边权为 \(0\) 的边,每次查询路径权值和即可,LCT 维护。
跳跃问题一般都可以考虑分块/根号分治。本题的正解是分块,
ZROI暑假5.A
不难发现经过一次上/下,再组合上左/右,所有的木块会集合在一个角落,而且不管后续如何移动形状不变,发现转一圈后原来的位置 \(i\to p_i\),再转一圈就是 \(\to p_{p_i}\)。于是我们直接记录每个位置顺时针/逆时针转动多少到哪个位置即可。
ZROI暑假5.B
可以考虑二分答案之后转化为判定。我们设 \(dp_{i,j}\) 表示在前 \(i\) 个点,得了 \(j\) 分的最小时间。这样子 DP 是 \(O(n^2k\log V)\) 的。首先可以优化掉转移的 \(n\),我们不必要枚举前面的所有决策点,发现一共只有 \(8\) 个位置,我们只需要对于每个位置找到最后一个能转移到当前位置的状态转移即可。同时发现这个状态里的 \(n\) 所能提供的信息只有当前位置和后面还能选什么点,我们可以通过 DP 出来的最小时间来得到第二信息,同时记录第一个信息,这样子这个 \(n\) 也被压缩掉了。于是最后复杂度就是 \(O((km^2+km\log n)\log V)\)。
ZROI暑假5.C
ZROI暑假6.C
构造双射 \(S\Leftrightarrow T\),使得 \(\operatorname{inv}(S)+\operatorname{inv}(T)=\dfrac{n(n-1)}{2}\),那么单个的。
ZROI暑假7.B
\(g_s=f_s-\sum\limits_{T\subset S且\min T=\min S}g_Tf_{S-T}\)
这个其实是集合幂级数 ln,可以做到 \(O(2^nn^2)\)。
ZROI暑假9.A
和 NOIP T3 一样走网格图即可。
ZROI暑假9.B
有一个结论就是 \(S-S\bmod x>\dfrac{S}{2}\) 或 \(=0\)。可以发现连续三个数要有连续两个数 \(\operatorname{lcm}<S\),那么选三个数优于选两个数。不过好像本题没用。
暴力做法及就是枚举所有转移点。对于第二问可以前后缀 dp 拼接,不需要在枚举每个分界点的时候都暴力点对,可以利用上一次的信息,每次只要 \(O(n)\) 拼接前后缀。时间复杂度 \(O(n^2\log S)\)。可以利用更快的 \(\gcd\) 技巧去掉 \(\log\)。
对于数据随机的情况,可以发现 \(val(i,j)=\max\limits_{k\le s,a_i|s,a_j|s}k\) 我们设 \(g_i=\max\limits_{a_j|i}\{f_j\}\)。转移的时候直接 \(f_i=\max\limits_{a_i|j}\{g_j+j\}\),由于数据随机,所以 \(\dfrac{S}{a_i}\) 的期望是 \(ln S\) 的。时间复杂度 \(O(ln S)\)。
NOIP1 A
学会预处理数字和数组 \(f_i=f_{i/10}+i\bmod 10\),复杂度 \(O(n)\)。
以及每个数开若干次方,也可以反过来每个数不断次方往上标记,复杂度 \(O(\sqrt n)\)。
一定要注意因为有两种边,所以边数数组要开 \(n+20\sqrt n\)。
NOIP1 B
有点危险,我怎么没有预处理回文串,在 dp 的时候判断的,下次要记住。
直接数位 dp,时间复杂度 \(O(n2^k)\)。
考场上想到回文串其实有效信息 \(2^{k/2}\),但是对于非回文串部分不知道该如何记录。
其实可以直接用 AC 自动机来记录下所有回文串,在 AC 自动机上跑就行了,这样子我们就只会跑一些有意义的部分。
NOIP3 A
就是如果不考虑爆 long long 的问题话,可以设 \(l_i=\operatorname{lcm(a_1,...a_i)}\),每次 \(l_{i+1}=\operatorname{lcm(a_{i+1},l_i)}=\dfrac{a_{i+1}\times l_{i}}{\gcd(a_{i+1},l_i)}\),最后算出来的 \(l_n\) 就是答案了,这显然是正确的。
计算 \(\operatorname{lcm}\) 的过程中显然无法直接对于 \(998244353\) 取模。直接算又会爆掉,所以我们考虑将 \(l_i\) 拆分,\(l_i=\prod\limits_{j=1}^ib_j\)。不直接维护 \(l\),而是通过 \(b\) 的乘积间接维护 \(l\)。于是有,
\(\begin{aligned}b_{i+1}&=\dfrac{l_{i+1}}{l_i}\\ &=\dfrac{a_{i+1}\times l_{i}}{\gcd(a_{i+1},l_i)\times l_i}\\ &=\dfrac{a_{i+1}}{\gcd(a_{i+1},l_i)}\\ &=\dfrac{a_{i+1}}{\gcd(a_{i+1},\prod\limits_{j=1}^i b_j)} \end{aligned}\)
可以如果直接计算 \(\prod\limits_{j=1}^ib_j\) 还是会爆 long long,注意到
于是直接枚举 \(1\) 到 \(n\),计算 \(b_i\)。最后答案就是 \(l_n=\prod\limits_{i=1}^n b_i。\)对于每个 \(i\),我们需要 \(O(n)\) 计算 \(b\) 的前缀积对于 \(a_i\) 的取模,于是时间复杂度就是 \(O(n^2)\) 的。