2023 NOIP 集训
Sdsc7.14
t1
一个小区,有 \(n\) 个人要住进 \(m\) 个房子,一个人有邻居的满意值是 \(a_i\) ,没有邻居的满意值是 \(b_i\) ,求怎么安排使得总满意值最大,需要让每个人都住进房子。
这是一个经典贪心问题——by Qingyu ,我们先假设所有人都没有邻居,然后按 \((a_i-b_i)\) 从大到小排序,将这些人作为有邻居的,直到所有人都能住进房子。
t2
给定 \(2n\) 个点,点有横纵坐标,我们称 一对点是好的,当且仅当横坐标相同或纵坐标相同。
最大化好的配对的数量,要求每个点都在一个配对中。
构造二分图的好题,完全不会。
应该是套路吧,二分图的左半部分对应每个点的横坐标,右半部分对应纵坐标,对于每个点 \((x_i,y_i)\) 连一条 \(x_i\to y_i\) 的边,问题转化为如何最大化 两条相连的边 的数量。
每个连通块都是独立的,有个结论是每个连通块都可以取到上界:\(\lfloor\frac{m}{2}\rfloor\) 。
构造方法是,每个连通块,在 dfs 树上,从下至上构造,类似这样,实际上很像dp对吧。
T3
给定一个 \(n+1\) 的条边的图,求 \(u,v\) 之间路径的个数。
树上两点间的路径是唯一的,多了两条边,路径数量最多为4:
- u - v
- u - a-b -v
- u - c-d -v
- u - a-b - c-d - v
只需要判断是否会出现下述三种情况,本质上是什么呢,本质上是树上询问 \((u,v)\) 和 \((a,b)\) 路径是否相交,如果相交才可以通过简单路径过去。
这个问题是一个经典问题,最为简单的方式是 dis(a,b)+dis(c,d)=dis(a,c)+dis(b,d)
或 =dis(a,d)+dis(b,c)
,复杂度为 \(O(\log n)\) 。
T4
给定一个长度为 \(n\) 的序列,定义 \(F(A)=\max ((a_1\&a_2\&...\&a_k)+(a_{k+1}\&a_{k+2}...\& a_n))\)
你可以至多进行一次交换 \(a_i\) 求 F 最大值。
也是 与 运算的老套路了,我们定义关键点当且仅当这个点对答案有贡献(负贡献):\(f(i)\ne f(i-1)\),不难发现这样的点只有\(\log\) 个。
由于不确定 \(k\) ,所以我们求一遍前缀关键点和后缀关键点,然后分类讨论。
- 交换两个非关键点,没有意义。因为与运算不会让答案变大
- 交换两个关键点,大力枚举 \(k\) 和前后缀关键点,复杂度 $O(n\log ^2) $
- 交换一个前缀关键点和后缀非关键点
- 此时后缀的总值为 \(f(k+1,n)\&a_i\)
- 也就是说,我们固定 \(i\) ,那么后缀的值已经确定了,无论选哪个 \(j\) 都一样。
- 那我们肯定选对前缀答案最有利的 \(j\)
- 注意 & 的性质,我们固定一个关键点 \(i,f(i+1)\) 的取值也只有 log 种(\(f\) 是单调不升的),我们枚举 \(i\) 和 \(f(i+1,k)\) 即可,记答案 \(v=f(1,i)\&f(i+1,k)\) ,同时你也得到了一个最大的 \(k\)(能保证后面的数尽可能大) 。
- 然后 \(O(n)\) 计算 \(v\&a_j,k+1\le j\le n\) 的最大值即可。总复杂度 \(O(n\log^2)\)
Sdsc 7.15
T1
图的模块度
简单模拟。
T2
一个数列 \(f_0=f_1=0\),
\(f_i=f_{i-2}\times f_{i-1}\times i\) ,求 \(f_n\) 的因数个数、\(n\le1e6\)
大家都知道因数个数等于指数加一连乘积对吧,所以我们先线性筛出所有 n 以内的质数。
考虑外层枚举质数 \(p\) ,定义 \(g_{p,i}\) 表示 \(i\) 的质因数分解后,\(p\) 的指数是多少,\(h_{p,i}\) 为 \(f(i)\) 质因数分解后 \(p\) 的指数。
得到了 \(h_{p,i}=h_{p,i-2}+h_{p,i-1}+g_{p,i}\) ,很烦,因为有后面的 \(g_{p,i}\) 而不能矩阵快速幂。
不过发现 \(g_{p,i}\) 实际上只有当 \(i\) 是 \(p\) 的倍数时才有值,即 \(\frac{n}{p}\) 个位置有。
所以我们对于这些位置暴力转移,剩下的fib矩阵快速幂,这样复杂度是:\(O(\sum_{i=2}^{i\in P} \frac{n}{i}\log i)=O(n*e*\log n)\)
发现我们完全没啥必要在这里做矩阵快速幂,提前预处理出 \(A^i,i\in P\) 即可。
这样复杂度是 \(O(π(n) \log n+ O(n\times e))\)
Summary
- 对于不能直接做矩阵快速幂的情况,多出来的部分可能个数不会很多。
T3
大模拟
T4
noip再补。
Sdsc 7.16
T1
给定一张图,有点权和边权,求出 \(max_{x,y}\{max(w_x,w_y)*dis(x,y)\}\) ,\(n\le1e5\)
因为要求最大值,所以不必麻烦严格按照规定做,我们枚举每个点,统计 \(max\{w_x*dis_{max}\}\) 即可。
\(dis_{max}\) 表示 \(x\) 能到的最远距离,有一个非常重要的结论是最远的这个点一定是树的直径两端点之一(下文也有,否则一定不是树的直径。于是先求一遍树的直径并找出两端点 \(a,b\) ,$dis_{max}=max(dis(x,a),dis(x,b)) $ 。
T2
给定一个无根树,等概率随机加一条边,每次给出 \(x,y\) ,询问 能使 \(x,y\) 在一个环里的情况中,环大小的期望是多少?\(n\le1e5\)
其实等价于分别求,能使这俩在同一种环的情况数,以及环长度的和。
需要分类讨论,两个点有祖先关系和没有祖先关系。
没有祖先关系的情况是简单的,情况数是 \(siz[x]*siz[y]\) ,大小和是 \(dis(x,y)*(siz[x]+siz[y])+\sum(dis(1,u)-dis(1,x))+\sum....+1*(siz[x]+siz[y])\)
对于有祖先关系的情况,方案数是 $siz[y]*(n-siz[x]) $ ,大小和,我们要额外记 \(D(x)\) 代表以 \(x\) 为根的子树,所有和 \(x\) 相连的线段长度和,发现这东西是树上前缀和的前缀和所以是可做的,故大小为 \(D(1)-(D(x)+dis(1,x)*siz[x])+D(y)+1\) 。
有点类似换根dp,所以官方做法其实是换根dp。
Sdsc 7.17
T1
求满足长为 \(k\) 序列数量:
- \(a_i\in[1,n]\)
- \(a_i\) 有序且互逆
- \(\forall x\in Z+\) ,以 \(a_i\) 的任意顺序作为排列,依次取模后结果相同。
手摸样例发现:x%a%b=x%b%a
的充要条件是 \(a\mid b\) 。
我们令 \(a_0\) 为最小的 \(a\) ,猜测充要条件是 \(a_0|a_i\) 。
于是我们枚举 \(a_0\) ,数量个数就是 \(\binom{\frac{n}{a_0}-1}{k-1}\) 。复杂度 \(O(n)\)
T2
Sdfz 8.10
Road Reform
给定一张图,构造一个生成树使得最大边权恰好为 \(k\),你可以通过若干次+1的操作或-1的操作,来完成,求最小操作步数
考场5min出正解调不出来了,好像是最小生成树没排序。
两次最小生成树,一次强制把k的前驱的边给加上,一次强制把k的后继的边给加上,当然可以取等,答案为两者最大值。
Gardening Friends
给定根为1的一棵树,移动根的代价是 \(c\),每条边的权值是 \(k\) ,定义一棵树的价值为根节点到子节点的最长距离,求价值最大值。
关于树的直径有一个极其简单的引理,同时也是两次dfs操作的理论基础,(当时)却是不会。。。
引理:树上任意一个点的最远点一定是 树的直径的两端点之一。
证明:反证法分三类讨论即可。
引理2:一棵树上多个树的直径,其关于根的深度有且只有两种。
那这样我们两(三)遍 dfs
,求出1到每个点的距离 \(dep_i\) ,再求出 \(x\) 到每个点的距离 \(d1_i\) ,再求出 \(y\) 到每个点的距离 \(d2_i\) 。
答案就是:\(Max\{-c\times dep_i+max(d1_i,d2_i)\times k\}\) 。
T3,4
扫描线和二维数点
Sdfz 8.15
T1 :Zero path
特别好的一道结论题,(其实考场上最后想到了
给定一个网格,网格上数字为1或-1,问从左上角到右下角是否有一条路径(只能向下或者向右),使得和为0.
遇到这种带有特殊性质的:点为1,-1:一定要考虑这个性质所带来的特殊结论,往往都是突破口。
我们注意到,一个点往右往下走,要么两个仍保持不变,要么相差2,另外如果n+m 是奇数则一定无解,考虑是偶数的情况。
令 A 为最短路的路径,B为最长路的路径,存放的是怎么走(Right or Down)。因为集合相同,那么我们可以不断通过交换相邻两个数来从A到B。
交换相邻两个数,对权值和产生的影响一定是+-2,又因为是偶数,所以最小值——最大值的过程中一定经过0,只需要判断最小值是否<0,最大值是否>0即可。
手模样例一般就可以得出结论
T2 P1034 [NOIP2002 提高组] 矩形覆盖
妈的怎么远古题都是傻逼搜索题呀。
T3 CF600E
dsu on tree/线段树合并 板子题
T4 篝火晚会
傻逼中模拟。
BCT23.8.18
本场 \(n,m\) 同阶,均为 \(1e5\) 级别。
T1
给定一个序列 \(a_n\) ,要求按顺序种上太阳,初始阳光为0,种下并不花钱,但是每秒会生产 \(a_i\) 的阳光,注意 \(a_i\) 有可能是负数,每秒可以选择种下下一棵或者等待,若某一时刻手里的阳光为负数则输出-1,求最短时间。
好像还真的是简单的反悔贪心,边输入边记录一个前缀最大值,如果当前的阳光为负数,那么不断增加这个前缀最大值直到大于等于 \(0\) ,额外增加的时刻就是增加前缀最大值的次数。
考场十五分钟切了。
T2
给定一个序列 \(a_m\) ,每个数大小不超过 \(n\) ,你有一个大小为 \(k\) 的容器,支持插入和删除操作,删除指定删掉最早访问的元素,你需要依次访问序列的数,注意到若此时容器内有当前要访问的元素则可以不必再插入,依次输出 \(k=1...n\) 的插入次数。
若当前序列为 1,2,3,2,1,2
,k=1
时答案显然是 6
k=2
时,第二个 \(2\) 和第三个 \(2\) 不必进入,答案为 \(4\) .
k=3
时,发现此时只需要把 1,2,3
给插进来就行,答案为 \(3\) 。
记录当前点上一个出现位置为 \(pos[a[i]]\) ,如果 \(i\) 可以在 \(k=x\) 利用到 \(pos[a[i]]\) ,那么需要保证中间数的个数不超过 \(x\),仔细想想,如果 里面有重复的数字? 根据这条规则,其对应的 \(x'\) 应该比 \(x\) 小,所以在 \(k=x\) 的条件下,里面重复的数字都可以利用,所以本质上 \(x\) 是中间不同数的个数。用主席树维护即可(HH的项链)。
求出 \(x\) ,相当于这个点对 \(ans[1]\) ~ \(ans[x]\) 都加 \(1\) ,再用个差分就做完了。
考场以为12点收卷于是调不出来摆烂,得知是半收卷,最后十分钟做完的,主席树的 \(n\) \(m\) 写反了。
T3
给定序列 \(a_n\) ,要求划分为若干段,每段长度为 \(1\) 或者 \(2\),使得最大值减去最小值的差最大。
我愿称为 线段树上区间 \(dp\) ! 总感觉做过一道类似的题。(不过这不就是动态dp吗——23.8.29)
我们发现 push_up(p)
本身就是一个非常像区间 \(dp\) 的东西,将两个东西合并。
令 \(t(l,r,0/1,0/1)\) ,表示该线段树上的区间 \([l,r]\) 已经覆盖,左边界是否为左端点,右边界是否为右端点,的最大值最小是多少?
那肯定是单个呀,一遍O(N)求最大值就完了。
话虽如此,但我们为了支持修改,就只能设这种在不用修改下显得非常智障的东西。
\(t(l,r,0,0)=Min\{max(t(l,mid,0,0),t(mid+1,r,0,0)),\ max(t(l,mid,0,1),t(mid+1,r,1,0)) \}\)
诸如此类,写在 push_up()
里_。
那么我们只需要 枚举最小值,由于一次只会增加一个最小值,那么我们每次只需要单点修改最小值所在的点变为正 INF。
具体的,把长度为1和所有长度为2的2n个元素排序后,从小到大,依次删除。
-
对于单个的元素,左闭右闭肯定是INF,左开右闭和左闭右开根据是否在边界上决定是否为
a[l]+a[l+1]
或者a[l]+a[l-1]
还是INF
。 -
对于两个的元素,强制让他俩拆开就行,对于 \(l\) ,左开右闭是 合法的,其余都是非法的,对于 \(r\) 同理。
为什么是对的,在没有修改的情况下,肯定选不到开区间的点,在修改后,有些地方变成正无穷,就必须使用这些点了。
T4
给定一棵树,点有点权,树上一条路径 \((u,v)\) 的价值是 \(\sum (x*w_k)\) ,其中 \(k\) 是路径上的点, \(x\) 是路径上小于等于 \(w_k\) 的点的个数。
求所有路径的价值和。
一眼考虑贡献!但是考场上想的是考虑点 \(u\) 的贡献,发现很难做。
正解是考虑 \((u,v)\) 的贡献, 设 \(w_u\le w_v\) ,那么贡献是包含 \(u\), \(v\) 的路径数量乘上一个 \(w_v\) 。
枚举点 \(v\) ,分类讨论。
- 若 \(u\) 在 \(v\) 子树内,那么
dfs
序上二维数点就行,数有多少个权值 \(\le w_v\) 的。 - 若 \(u\) 是 \(v\) 祖先,那么
dfs
的时候用一个平衡树来维护。 - 剩下的情况,也就是两者有一个 \(lca\) 的情况,就是整棵树 \(\le w_v\) 的减去上面两者即可。
所以考虑贡献有没有什么技巧。
BCT 8.19
T1
因为缺省源内 \(N=1e5\) 导致白丢 \(30pts\) ,警钟长鸣。
T2
给定 \(n\) 个字符串,从中选出 \(k\) 个字符串,你的目的是让这 \(k\) 个字符串中某两个的最长公共前缀的最大字典序最小。 \(n\le10^5\)
赛时错误的想法是依次枚举每一个点作为最大LCP,正确的思路是逐位确定答案。
为什么呢?发现这个答案肯定是可以逐步确定的对吧。
从头分析,一个点 \(u\) 能作为答案,那么选中的 \(k\) 个点该怎么分配呢?
-
对于字典树左边的点显然是可以任意选的
-
\(u\) 子树的点,不能使他们产生新的,更深的lcp,所以每个儿子只能选一个。而且至少选两个儿子。
-
\(u\) 到根链上右边的点,也是不能让他们产生新的lcp,所以每个儿子只能选一个。
假设当前已经选中了答案的前 \(k\) 位,判断第 \(k+1\) 位是否能为 \(c\) ,当且仅当:
-
之前的选中的点
-
当前点所代表字符串的个数
-
1~c 位全部选
-
c+1位到26位只能选一个
-
这些和加起来 \(\ge K\)
那么可以选择这一位,并且将累计的 \(num\) 减去 第 \(c\) 位全部选的情况, \(K\) 同样可以减去 超出的值,递归到下一层。
直到只需要加上 大于等于 \(2\) 个 只能选一个的儿子和本身,就可以 满足要求,便停止递归。
实现起来还蛮复杂的,因为是随机的数据,所以std也没判断 要求大于等于2个儿子和本身。把小王Hack了(
逐位分析。
T
给定一个长度为 \(n\) 的字符串,对于每一个后缀,求出他们能有多少种:“AABA”类型的方案,其中AB均不为空。 \(n\le10^5\)
关键在于转换,显然我们要枚举 \(A\) ,因为\(A\) 一定是原字符串的一个后缀,然后再找前缀= \(AA\) ,而且长度 \(\ge 3|a|+1\) 的后缀数量。
考虑将所有后缀 按照哈分+二希排序,得到按字典序排序好的字符串,我们再枚举 A ,那么所得到的 以AA为前缀 一定是在一个区间内,这样就可以哈分+二希找出这段区间,具体地,找出第一个前 \(2|A|\) 的 Hash 大于等于 \(2A\) 的,再找出第一个 前 \(2|A|\) 的Hash 大于 2A的,但是怎么感觉这样不满足单调性呀,你想想因为有个取模所以按字典序排完,hash值也是排好的吗?
然后又要保证长度,就是一个 simple 的二维数点问题啦。时间复杂度 \(O(n \log^2)\)
BCT 8.20
T4
给定一张图,每个点有点权 \(a_i\) ,但是相连的两个点所选择的点权必须相等,你要对于每次删除一条边 ,求出此时可以选到自己的点权的点有多少个。
详情揭秘如何 \(O(1)\) 支持插入,删除,集合众数的出现次数。
-
维护两个数组 \(f_i\) 表示 \(i\) 的出现次数, \(g_i\) 表示 出现次数为 \(i\) 的元素个数。
-
对于加入元素 \(x\) ,
g[f[x]]--
,f[x]++
,g[f[x]]++
,此时 \(ans=max(ans,f[x])\) -
对于删除元素 \(x\) ,
g[f[x]]--
, 此时若g
等于 \(0\),那么 \(ans=ans-1\) ,f[x]--
,g[f[x]]++
。
那这样就好做了,如果这条边不是割边,一定不会影响连通性,答案就是不删边的答案。
割边的情况,我们将边双缩点后的树形图上 dfs,结合上述我们发现的牛逼小清新数据结构,以及dsu on tree,就可以 \(O(n \ log n)\) 做了。
不过 dsu on tree 不敢写。要是我很会就不会写2h线段树合并了。
好好好,std 250行是吧。
BCT8.21
T1
7层 分层图上跑最短路。
或者叫,最短路图?
T4
给定 \(n\) 个数 \(a_i\) ,若两个数 \(a,b\) 满足 \(\gcd(a,b) \ge m\) ,则可以选择 \(a,b\) 其中一个删去,求最大的 \(m\),使得经过 \(n-1\) 次删除后只剩下一个点。\(n\le10^4,a_i\le10^7\)
-
类似于“每次删除一个,最后剩下一个“的具象化结构实际上是一棵树。最后剩下的点就是树根。
-
那我们最终要求的最小 \(m\) 实际上就是树上 最小的一条边。
-
类似最大生成树,不断从树上连边,关键在于判断连通性——并查集。
-
但是边的个数是 \(n^2\) 级别的,再加上一个 \(log\) 的排序。
-
发现 \(a_i\le 10^7\) ,一个数的因数个数是 $O(\sqrt{n}) $ 级别的,可以接受。于是把所有数的因数存到
vector<>
里,不会MLE。 -
最刺激的地方来了,不能完全模拟 \(kruskal\) 最小生成树的建法,只需要模拟两个点是否联通即可。也就从大往小枚举边(gcd),看看其两边的点是否在生成树(并查集)内,如果不在就加进来。直到只剩一个并查集。 -
错了!自己考场上写的就是正解,只是没调出来。
-
从大到小枚举 公因数,不断找两个公因数的倍数合并。因为有
后面是啥?——9.24
BCT8.22
T1
给定一棵树,若干个点可以选择,选择其中 \(m\) 个点,使得其中 最远的两个点距离最小。\(n \le 3000\) 。
-
是不是可以淀粉质呀(雾
-
一眼二分答案(距离),check怎么写?
-
考虑树形 \(dp\) ,\(dp_{u,i}\) 表示以 \(u\) 为根的子树内,选择了 \(i\) 个点,距离最远的一个点的距离。
-
很难转移,考虑状态结果互换。
-
\(dp_{u,i}\) 表示以 \(u\) 为根的子树,距离最远的一个点的距离是 \(i\) ,最多能选择多少个点。
-
转移: $dp_{v,k}\to dp_{u,max(k,j)}\ $ ,具体地, \(j\) 枚举最长距离, \(k\) 枚举子树的距离,即 \(mid-\)
补
BCT8.23
T3
给定一张有向图,求出一棵满足各点到 \(1\) 最短路长度不变的 最小生成树。
-
最短路图。
完全没听过呀,只需把所有 \(d_v=d_u+w\) 的边给加进来就行。
-
有向图最小生成树
完全没学过呀,有一种算法叫做“朱刘算法”求最小树形图,好好好没听过。
不过我们完全不需要用他,跑 \(kruskal\) 就行了。
T4
\(n\) 个人在玩击鼓传花的游戏,有两个花,初始分别在 \(a,b\) 手里,在 \(T\) 轮游戏中,每次需要把其中一朵花传递到 \(s_i\) 手中,另一朵花不能操作,求最小操作次数。
-
感觉是 \(Smeow\) 之前在日照出过的题?
-
考虑一个 \(O(n^3)\) 暴力,设 \(dp_{i,j,k}\) 表示 第 \(i\) 轮游戏,第一朵花在 \(i\) 手里,第二朵花在 \(j\) 手中的操作数。
-
显然第 \(i\) 轮手里其中一朵花一定在 \(s_i\) 手里,另一朵在 \(j\) 手里,所以优化到 \(O(n^2)\) 。
有转移方程 $dp_{i,j}=\begin{matrix} dp_{i-1,j}+|s_{i-1}-s_i| ,j \ne s_{i-1} \ Min{dp_{i-1,k}+|k-s_i|},j=s_{i-1} \end{matrix} $。
上面那个复杂度是 \(O(1)*n\) ,下面那个复杂度是 \(O(n)*1\) 。
-
还挺复杂的,考虑怎么做到 \(O(n\log n)\) ,用线段树优化。
感觉是为数不多的用线段树区间修改优化 \(dp\) 的,上面那个显然就是一个区间加法。加上一个 \(|s_i-s_{i-1}|\) 的常数。——
后面9月校内模拟赛又出了一个Bakery
下面那个玩意再拆一拆,把绝对值去掉:
-
\(dp_{i,s_{i-1}}=Min\{dp_{i-1,k}+|k-s_i| \}\)
这样就可以对 \(k<s_i\) 的,求 \(Min \{a_i+i\}\) ,对后面的,求 \(Min\{a_i-i\}\) ,好像比较困难,还去u群问了,其实很简单,你在求 \(dp_{i-1}\) 的时候是知道 \(s_i\) 是多少的,求的时候记录一下
minn
即可。后面是一个单点修改、
这样,不需要开二维数组,只需要用一个线段树维护,支持上述三种操作。最终答案即 \(\min dp_j\) 。
挺牛逼的题,有空就实现一下。
-
BCT8.24
T2
最大全1子矩阵问题
记录每个位置往上走最长有多少个 \(1\),可以从上一行转移下来 。转换成直方图最大子矩阵,单调栈即可。
单调栈:记录每个位置开始向右能扩展多少个矩形。每次单调栈进来一个较小的,都把比他大的弹出。每一步统计选 \(i\) 的面积大小。注意在最后新加入一个高度为 \(0\) 的。
笛卡尔树也可以,复习一下:
将下标作为 \(val_i\) ,\(h_i\) 作为 \(rnd_i\) 建立小根堆,建立一棵笛卡尔树,每个节点都是一段连续的区间,且子树的根节点的 \(val\) 就是这段区间的最小高度,乘上这个点所代表区间的长度即可。
T3
-
走到第 k$ 轮的概率是 0.6^k$ ,所以全排列在随机数据下跑得飞快。
-
从后往前枚举,增加在第 \(i\) 位,增大到 \(x\) 。
T4
博弈论
补
BCT8.25
补
BCT8.26
T4
一张 \(n*m\) 的网格,可以黑白染色,当某一行或者某一列全为 \(0\) 或者全为 \(1\) 时,对答案有 \(1\) 的贡献,求贡献为奇数的网格方案数。\(n,m\le1e6\) 。
-
枚举至少打破多少个条件。
\(\sum(-1)^i*...\)
打破刚好奇数个条件的答案?
\(\sum(-2)^{i-1}\)
刚好打破偶数个条件?
\(\sum-(-2)^{i-1}\)
-
容斥系数?
最普通的:枚举至少打破0个,1个方案,2个方案,,,,n个方案。用系数乘起来。
-
至少打破0个为什么是1?
刚好打破0个的方案——1。只会在这里统计,且是最后一次有机会统计的地方。
-
至少打破1个
刚好打破1个的方案——在0处统计,在1处统计,希望他统计0次,而在0处统计1次,故-1
-
刚好打破2个
应该统计0次,但是在0处统计 \(C(1,n)\)
-
分类讨论
打破 \(i\) 个行:\(\sum_{i=1}^n (-2)^{i-1}*C(i,n)*2^i*2^{(n-i)*m}\)
-
列对称
-
都打破
\(\sum\sum(-2)^{i+j-1}*2*2^{(n-i)*(m-j)}\)
-
-
二项式定理
$\sum $
Sdfz 9.23
T1
给定一棵 二叉树,初始时刻 \(1\) 号点感染了病毒,每一回合病毒都会传播一层,但是每一回合你都可以删掉一个点来阻断传播,求能保留的最多点(不算删掉的点)
如果看到二叉树是好做的,看不到是没法做的。
贪心贪子树大小肯定是错的,和树的结构(链)是有关系的,所以dp求解。
T2
给定 \(n+1\) 个数 \(a_i\) 和 \(n\) 个数 \(b_i\) ,对于每个 \(i\) ,求出删掉 \(a_i\) 后,剩下的数两两配对,使得 \(a_i-b_j\) 最大值最小。\(n\le1e5\)
显然要排序,对答案有影响的只有最大的那一个,所以配对一定不会相交。删掉一个数,左边的仍是直上直下的配对,右边的是 \(b_i 和 a_{i+1}\) 配对,所以我们预处理一个前缀后缀最大值就可以 \(O(n)\) 做了。
差点死因:用 map
记录下标,但是显然这不是个排列。
T3
有 \(n\) 棵树,每棵树有高度 \(h_i\) ,有 \(m\) 条边权为 \(w\) 的双向边连接两棵树,但是在飞翔过程中会下降 \(w\) ,你需要保证飞行是合法的,即不能落在地上,也不能超过树顶。起点是第一棵树的 \(x\) 高度,终点是第 \(n\) 棵树的最高点,求最短路。\(n\le1e5,h_i\le1e9\)
最暴力的方法是每棵树都建出 \(h_i\) 个点,复杂度 \(O(h_i(n+m \log m))\) 。
但实际上这题是个贪心,我们先考虑起点高度是 \(0\) 怎么走,发现只要走到 \(h_u=w\) 时就直接飞行到 \(h_v=0\) 即可,如果再往上走,那么有可能还要再往回走,因此这样是最优的。对于走不到的情况,在加边过程中舍弃即可。
如果高度是 \(x\) ,那么会往下走,走到 \(h_i+w\) 一定是优的。
如果能正常飞,那就不需要走。
T4 Bakery
区间加法线段树 优化dp
将 \(n\) 个数分为 \(k\) 段,使得总价值最大,定义一段的价值是该段不同数字的个数、 \(nk \le 1e5\)
不加优化的状态方程很好想,
但一上来先打主席树就彻底输了,瓶颈压根不在于处理区间不同数个数,暴力做枚举就行。
线段树优化dp?后面的东西在括号里面,也不能做。
考虑贡献
当我们求到一个数 \(a_i\) 时,\(a_i\) 对 \(dp\) 有贡献的是 \(dp_{[pre+1,i-1],k}\) ,且贡献为 1 ,所以线段树实现一个区间加法+区间最大值就可以了。
是不是挺像莫队?
Nfls 9.25
Booms 60 but 0 how fucking fhq+bit?
T1
给定一个长度为 \(n\) 的字符串,多次询问区间 \([l,r]\) 的最长回文子串。\(n\le 3e5\)
遇见回文串,可以先 \(manacher\) 简化一下,并求出每个点的最长回文半径 \(p_i\) 。
暴力的做法是,每次在区间内枚举 \(j\) ,答案就是 \(Max\{ min(p_i,j-L,R-j)\}\) 。
实际上这就是一个 最小值最大 问题,考虑二分答案 \(ans\) ,那么 \(j\) 所在的区间一定是 \([L+ans,R-ans]\) ,且要满足这个区间内存在一个值等于 \(p_i=ans\) ,也就是,只需要保证 \(\exist \ p_i\ge ans\) 即可,因为 \(p_i\) 是静态的,所以直接 \(ST\) 表维护即可。
对 \(manacher\) 后的新串操作需要注意前后对应关系。
所以根本不需要树套树对吧————
T2
给定一个长度为 \(n\) 的小写字母字符串,其中有些位置是
?
,求有多少种方案能使得整个串中"sakana"
和"chinanago"
两个串的出现次数相同。 \(n\le 1e4\)
首先我们发现 两个字符串是完全不交的 ,因此我们有暴力 \(dp_{i,a,b}\) 表示 有 \(a\) 个字符串1,\(b\) 个字符串2 的方案数。
但这样是三次方的,对于“相等”的问题,一种常见的套路是 改状态设计为 \(dp_{i,j}\) 表示 两种字符串的差为 \(j\) 。
转移有
孙老师表示完全不能理解呀,被他一说感觉加深了对dp的理解呢。
首先你新加一个字符,初始值是从上一位转移过来的,如果此时生成一个新串,那对 \(j\) 这一维是有贡献的,所以还要从 \(dp_{i-6,j-1}\) 转移过来,但是因为中间全部合法的部分算了两遍,所以减去一个 \(dp_{i-6,j}\) 。孙老师疑惑这里为什么不是 \(j-1\) 呢,我们考虑他的实际意义,实际上后面少了一个系数 \(*1\) ,意味着后面这几位都固定好了——。
T3
给定一张图 ,和参数 \(q\) ,求走 \(1...q\) 条边的最长路,\(n,m\le1e3,q\le1e9\) 。
当 \(q\le m\le1e3\) 时,暴力做就好。
当 \(q\ge m\) ,我们一定可以走到一条最大的边,然后不断在这条边上走,使得总答案最优。而前面的过程一定是从1开始的最长路。
于是我们暴力枚举 \(i\to j\)
T4
Nfls 9.26
T1 有限小数
求出有多少对 \((x,y)\) 满足 \(\frac{x}{y}\) 是十进制有限小数,\(x,y\le1e11\)
小学数学经典结论,十进制有限小数等价于 \(\frac{a}{2^p5^q}\) 。
这里还没有考虑到约分,于是有 \(\frac{ak}{2^p5^qk}\) ,需要满足 \(k\) 既不是 \(2\) 的倍数也不是 \(5\) 的倍数。
令 \(2^p5^q=a_i\) ,答案即为 $\sum_in\sum_k \lfloor\frac{n}{k}\rfloor,a_i\le n,k\mod 2,5 \ne0 $ 。复杂度 \(O(e*n^2)\) 。
考虑更换枚举顺序,外层枚举 \(k\) ,则有 \(\sum_k^n d* \lfloor\frac{n}{k}\rfloor,d是合法a_i 的个数,k\mod 2,5 \ne0\) 。\(d\) 随 \(a\) 增大单调递减,代码里用 while()
处理。所以求和符号是怎么变化的呀。
发现后面是个整数分块的形式,但是又不大经典。
回顾一下整数分块都是怎么做的?\(\forall x\le \sqrt n\) 直接枚举做,\(x>\sqrt n\) ,我们枚举结果 \(\lfloor\frac{n}{k}\rfloor\) ,确定出 \(k\) 的范围 \([l,r]\) 。
此时满足条件的 \(k\) 的个数是好求的,经典容斥:l-r+1-P(l,r,2)-P(l,r,5)+P(l,r,10)
。其中 \(p(l,r,k)\) 表示区间 \([l,r]\) 有多少 \(k\) 的倍数,这一步可以差分得到。
复杂度 \(O(\sqrt n)\) 。
T2 考 考试
求第 \(k\) 个满足十进制的表示是其二进制表示后缀的数,\(k\le3000\)
例如 \((10)_{10}=(1010)_{2},(110)_{10}=(110,1110)_2\)
结论:\(10^k\) 的二进制结尾一定有且仅有 \(k\) 个 \(0\) :证明:\(10^k=2^k\times5^k\)
所以,若 \(x\) 不满足条件,则 十进制 \(x\) 前加一个 \(1\) 仍然不满足条件。
于是,我们只需要对满足条件的十进制后缀,前面加上1或者0。
这个过程是用一个堆来实现的,初始放一个0,存三个参数:大小 \(val\) ,位数 \(l\),是否有前导0。
每次从堆中取出一个位数最小,位数相同值最小的,在他前面加1,0,检查是否还合法:
若在前面加1:如果加上10^k后,二进制上那一位(k+1) 还是1,则说明合法
若在前面加前导0,本质上相当于只能保证二进制前 \(k\) 位不变,第 \(k+1\) 位如果变成1的话,就和加0不符,所以判断 \(x\) 第 \(k+1\) 位是否为0 。
如果一个数没有前导0,cnt++直到k。
但是这样在k=2000就爆int128了,恶毒的出题人还让我们写一个只包含01的高精度。
Nfls 9.28
T1 倍数区间
定义一个区间是好的,当且仅当存在一个数是这个区间内所有数的因数,求最长合法区间长度和所有最长合法区间的左端点。
$O(n\log^2) $ 是容易想到的,\(ST\) 表维护 \(gcd\) ,二分序列长度即可。
又因为 \(ST\) 维护的 \(gcd\) ,线段树也可以做,所以线段树二分,对于每个位置 \(i\) ,在线段树上找到这个叶子,往上跳再往下跳吗。不会、
T2 飞翔的鸟
在玩飞翔的小鸟
每次可以从 \((x,y)\to (x+1,y),(x+1,y-1),(x+1,y+1)\) ,且 \(y\in [1,k]\) 。
有一个位置有障碍,覆盖了 \(y\in [1,a] ,[b,k]\) 的位置。
要想从 \((1,\frac{k}{2})\) 飞到 \((n,\frac{k}{2})\) ,障碍物在 \([2,n-1]\) 的某一个位置随机出现。
求期望可行的飞行路径数量。 \(n\le10^9,k\le130\) 。
考虑 \(dp\) ,因为 \(k\) 很小,考虑构造矩阵转移。
\(Ans=\sum _{i=2}^{n-1} A^{i-1}\times B\times A^{n-i}\) ,
Bct 9.30
T1
躲避滚石
参考系变换,相当于滚石不动,人在动。
注意瞬时移动和单位时间移动的区别
T2 小木棍
两部分截出的价值相等的点是好计算的,这些点是关键点,关键点之间的长度都有贡献。
T3 教室分组
将集合 \(a\) 分为若干组,使每组人数均为奇数,且人数在 \([l,r]\) 范围内。
定义一组的价值是这组的中位数,一个分组方案的价值是所有组价值的平均数。你要求分组方案价值最大。
\(n\le10^6,a_i\le2^{30}\)
首先排序肯定是要做的。
我们把每一组中位数称为 \(B\) ,小于和大于中位数的部分称为 \(A\) 和 \(C\) 。发现最优方案中,最小的 \(B\) 一定大于最大的 \(A\) ,否则一定可以通过交换两者而使得方案数不变的情况下更优。
我们希望 \(B\) 尽可能都在数组后部,于是我们枚举最小的 \(B\) 的位置,只需检查
Sdfz 10.8
T2
\(n\) 个人有坐标 \(x_i\) 和影响力 \(e_i\) ,当你对 \(i\) 赠送一本书时,所有满足 $ {x_i-x_j}\le e_i-e_j$ 的 \(j\) 都会买这本书,求最少送多少书,可以让所有人都有书。
绝对值先拆式子,有:
\(x_j-e_j \ge x_i-e_i (x_i\ge x_j)\)
\(x_j+e_j\le x_i+e_i(x_i\le x_j)\)
不看括号内条件的话,带绝对值的式子和下面两条是完全等价的,也就是说:如果一个 \(j\) 同时满足上述两条,那么其一定满足原条件。
可以转换成线段覆盖问题,对于一个 \(i\) ,左端点为 \(x_i-e_i\) ,右端点为 \(x_i+e_i\) ,如果另一个 \(j\) 的线段被 \(i\) 完全覆盖,那么 \(i\) 就能影响到 \(j\) ,于是只需求出最少需要多少线段可以使所有线段被覆盖。排序后贪心选。
也可以以 \(x_i-e_i\) 为 \(X\) 轴,另一个为 \(Y\) 轴,相当于能够影响所有 比 \(X_i\) 大,比 \(Y_i\) 小的,也就是点右下方的一个矩形,相当于一个二维数点,按 \(Y\) 轴排序后,从上往下枚举,如果这个点在之前已经被影响到了就不选,否则就选。
T4 [P5852 Bessie's Snow Cow P]
给定一棵树,点有颜色(可以叠加)。两种操作:
- 将 \(x\) 整个子树增加一种颜色 \(k\)
- 查询 \(x\) 整个子树,每个节点的颜色数量之和。注意不是整个子树的颜色数。
\(n,k\le 10^5\)
我们开 \(k\) 个 std::set
维护颜色为 \(i\) 的 不交节点区间 ,换句话说,存下的是若干棵不交的子树的根节点。体现在操作中的就是每次加入点 \(u\) ,要删除 set
内 \(u\) 子树的所有点。注意每个点只会被加入一次删除一次,所以复杂度是 \(O(n\log n)\) 。
对于查询的操作,我们仍用线段树,记 \(t_u\) 为 \(u\) 的不同颜色个数,查询就是子树和。
对于修改的操作,如果 set
里已经有其祖先了,直接跳过不管;否则,我们删除 set
内一个点时,要将其贡献清除,也就是这个子树区间减一。最后加入 \(u\) ,整个子树区间加一。
代码难点在 set
遍历上:
找祖先:如果存在祖先,一定是 当前 \(u\) 的前一个点(以 dfn
为键),否则如果前一个不是祖先,那么就没有祖先,
注意 set
的边界问题:指针加减前后要判断和 begin()
与 end()
是否相等。
( set.erase
后寻址不连续,所以必须用 lower_bound
找到下一个点。 )
nfls 10.9
T1 华灵
构造
你被要求构造一个 \(n*m\) 的矩阵,你可以在每个位置填一个左括号或者右括号,求最多合法括号序列的行和列是多少。你需要输出方案。
构造题,完全猜错,在小数据下是对的,和指数暴力也拍了,屁用没有。
赛时的结论是 \(n+\frac{m}{4}\) ,但实际上考虑一个大于6的就可以想到,最优的方案数是 \(n+m-4\) 。
怎么构造呢?第一列,第一行,最后一行,最后一列都不合法,而且均全部是左括号和右括号,你发现中间是全部合法的。
但是这是在 \(n,m\) 较大的情况,若较小的情况,例如 2 和 2,考虑牺牲一半的行和列:答案为 \(n+m/2-1\)
()
()
T2 最近公共祖先
均摊分析
一棵有根树,点有点权,初始全部为白色,你有两种操作:
- 将 \(u\) 修改为黑色
- 给定一个 \(u\) ,查询 \(lca(u,v)\) 的点权最大值,且 \(v\) 是黑色点。
暴力比较好做,dfs建出序后,每次修改后,相当于 \(1\) 到 \(u\) 这条路径上的点都可以作为 \(lca\) 有贡献。
具体的,每次首先将 \(u\) 的子树全部和 \(w_u\) 取 \(\max\),不断跳父亲,直到 \(1\) ,每次将除了上一步的子树以外的其它子树,和当前根 \(x\) 取 \(\max\) ,记录一个 \(las\) ,每次修改两段即可,而每次询问子树查询即可。线段树维护单点查询,区间取 \(max\) 。甚至不需要 \(tag\) (或者称为 标记永久化)即可。这样复杂度是 $O(qn^2\log) $ 的。
但是这样其实很多是没有必要的,如果在向上跳的过程中,如果一个点已经被被访问了,那它至多有一个子树没有被更新,而它的祖先,一直到根,已经访问过了,再来一遍是完全等价的,都会修改除了当前子树的其他子树,所以我们用一个 \(vis\) 记录一个点是否被访问,一个点最多被修改两遍子树,均摊复杂度是 \(O(q\log n)\) 的。
nfls 10.10
T2 完全背包问题(同余最短路)
\(n\le 50\) 件物品有体积 \(w_i\le 10^4\) ,另给两个参数 \(L,c\) ,表示体积超过 \(L\) 的物品总共最多选 \(c\) 件 \(m\le50\) 次询问,给定一个背包容量 \(W\le 10^{18}\) ,询问能否恰好填满背包。
首先排序把 \(w_i\) 分为两部分。令 \(dp_{i,j}\) 表示选 \(i\) 件超过 \(L\) 的物品,体积 \(\bmod w_0=j\) ,所需要的 最少 体积。
对于小于 \(L\) 的部分,跑一遍同余最短路即可把 \(dp_0\) 处理完。具体的,枚举每个物体 \(i\ge1\) ,枚举 \(j \in[0,w_0-1]\) ,每次从 \(j\) 建一条 \((j+w_i)\bmod w_0\) 的有向边,边权为 \(w_i\) ,跑最短路,实际是为了处理有后效性的dp问题。这样得到的最短路 \(d_i\) 和 \(dp_{0,i}\) 的含义是相同的。
对于大于 \(L\) 的部分,因为范围小,所以直接大力 \(dp\) ,填表不好做,考虑刷表法,有:
最后统计答案,只需保证 \(\exist \ dp_{i,W\bmod w_0} \le W\) 即可,含义就是你可以加若干次 \(a_0\) 达到 \(W\) ,但是不能现在已经超过 \(W\) 。
T3 ydc的大树 (CF348E Pilgrims)
简化题意
给定一棵已经确定黑白染色的树,边有边权,其中有 \(m\) 个黑点,其它都是白点。
对于一个黑点,我们定义他的好朋友是离他最远的黑点。显然,一个黑点可能有多个好朋友。
现在要删除一个白点,使得删除后,不能到达任意一个好朋友的黑点数量尽可能多,求出这个数量的最大值,以及多少个白点删掉后满足这个最大值。
看到最远点想到树的直径两端点,但是显然此时的树并非原树,我们只会用到黑点,因此求直径时,实际上这棵树是只有黑点的虚树。我们两遍 dfs
跑出树的直径 \(len\) 。
树的直径的长度是抽象的,但是直径两端点却是不唯一的,一个trick是树的直径的中点是唯一的(NOIP2007 树网的核),注意这里的中点是 离 \(\frac{len}{2}\) 最近的点,如果是两个点则任取一个。这里的中点有可能是白点。
找到中点后,我们把中点提拉成根,变成一棵有根树,此时任何一个黑点想要到达他的好朋友,一定要经过根。
然后我们枚举要删除的白点 \(u\) ,白点子树的所有黑点肯定都算入答案,另外我们要分类讨论。其依据是,整个树的直径,要么是一条从根往下延伸的最长链和另一条次长链,要么是两条最长链。(实际情况可能是若干条)
-
这棵树由一条最长链和若干次长链组成,且 \(u\) 在最长链上:
此时,这条最长链上的,非 \(u\) 子树的黑点,仍然可以到达他们的好朋友,即次长链的最深黑点。而除了他们,其他黑点都到达不了他们的好朋友,即最长链的最深黑点。
-
这棵树由一条最长链和若干次长链组成,且 \(u\) 在次长链上:
此时,这条次长链上的,非 \(u\) 子树的黑点,仍然可以到达他们的好朋友,即最长链的最深黑点。但是,唯一的最长链上的黑点都到达不了他们的好朋友,即次长链的最深黑点。
-
这棵树由且仅由两条最长链组成,且 \(u\) 在最长链上:
此时, \(u\) 这条最长链上的,非 \(u\) 子树的黑点,仍然可以到达他们的好朋友,即另一条最长链的最深黑点。但是,另一条最长链的所有点都到达不了他们的好朋友,即 \(u\) 这条最长链的最深黑点。
当然,如果有多条最长链则不会出现此情况。
对于上述信息,笔者的处理方式是若干遍 dfs
分别处理出 在以直径中点为根的树中,\(dp_i\) 表示 \(i\) 子树的最深黑点的深度,\(anc_i\) 表示 \(i\) 的祖先是根的哪个儿子,最长链的数量 \(cnt\)。这样如果 \(dp_u=dp_{root}\) ,则说明 \(u\) 在最长链;若 \(dp_u+dp_{root}=len\) 则说明 \(u\) 在次长链。
[评测记录](Submission #227608771 - Codeforces)
nfls 10.12
T1 yxh 与数组
给定四个数 \(a,b,c,d\) 判断 \(a\) 到 \(b\) 的乘积是否是 \(c\) 到 \(d\) 的乘积的因数, \(10^7\) 。
显然是存不下的,而且模意义下没有整除的性质。
注意到 \(a\) 是 \(b\) 的因数的充要条件是 \(a,b\) 质因数分解后 \(a\) 每个质因数的指数都小于等于 \(b\) 的。
我们发现 \(1e7\) 内素数个数只有 \(6e5\) 个,枚举每个质数,检查其在区间 \([l,r]\) 对指数的贡献。可以差分+类似容斥但不需容斥做。
我们还要枚举每个质数的若干次幂,这样总复杂度是 \(O(n\log n)\) 。
T2 谦逊
给定 \(n,k\le 10^{15}\) ,两种操作。
- \(n=n+k\)
- \(n\) 变为其十进制表示下,各数位之和。
求 \(n\) 最小能变成多少,并求出变成最小值,所需的最少操作数。
对于十进制表示下各数位之和的定理:
类似小学数学的 快速判断一个数是不是 \(3\) 或者 \(9\) 的倍数。
于是我们确定答案一定在 \([1,9]\) 内,而且粗略估计 \(1e15\) 的数,只需做 \(3\) 次操作2 变成个位数。
但是中间会穿插若干个操作1,注意到 只有 \(n+k,n+2k,...n+8k\) 是有意义的,因为在模9意义下循环。
所以总操作不会超过13次,直接暴力 dfs
即可。
T3 基础fake 练习题
给定一棵树,点有点权 \(c_i\),给定 \(m\) 种覆盖方案 \(u_i\to v_i\) ,每一个点上的覆盖次数不能超过 \(c_i\) ,求最多可以使用多少覆盖方案。
考虑 贪心,不妨令 dep[u]<dep[v]
我们肯定优先选择那些 \(u\) 尽可能深,且 \(v\) 尽可能浅的方案。
用线段树暴力树剖即可。
Nfls 10.13
T1 橙子
给定 \(n\) 个数 \(a_i\) ,若干次询问,每次询问 \([l,r]\) 的区间子区间,异或和的异或和。
异或满足结合律和交换律,只需判断每个 \(a_i\) 在这一串出现次数的奇偶性。对于一个 \(a_i\) ,在该区间内,左边有 \(i-l\) 个数,右边有 \(r-i\) 个数,出现次数就是 \((i-l)(r-i)\) ,当长度为偶数时,左右至少有一个是偶数,总结果就是偶数,否则,当 \(i\) 为奇数时是结果是奇数,为偶数时结果是偶数,或者反之。用两个树状数组维护奇数位和偶数位就可以。
T2 椰子
给定 \(n\) 个椰子的硬度 \(a_i\) ,一次操作可以让一个椰子硬度减一,但是这些椰子的顺序是不知道的,求打碎 \(m\) 个椰子至少需要多少操作。\(n,m\le5000\)
这个题相当于有神秘力量不断地将最硬的椰子给我们敲,我们永远会得到最坏情况。
结论:敲掉任意一个硬度为 \(x\) 的椰子,所有硬度 \(>x\) 的椰子都至少被砸了 \(x\) 次。
考虑反证法,如果一个硬度 \(>x\) 的椰子敲了少于 \(x\) 次,但是一个硬度等于 \(x\) 的椰子被砸碎了,神秘力量肯定不会让我们这样做。而是会给我们那个硬度大的椰子砸,而导致这个椰子并没有碎,这是牠想看到的。
因此我们的策略大概是,(先从大到小排序后)选择一个基准 \(h_i\) ,一直敲,如果椰子没有碎就换下一个椰子,如果碎了,将 \(h\) 降低。
于是 DP 是正确的,设 \(dp_{i}\) 表示对于前 \(i\) 个椰子,敲碎了 \(j\) 个,最少砸多少次,转移则是枚举当前选择的基准 \(a_i\) ,敲了多少个椰子(一个后缀),转移有 $dp_{i,j}=\min {dp_{k,j-1}+a_i \times (i-k) } $
暴力是 \(O(n^2m)\) 的,不难发现可以斜率优化,复习一下:用 \(b\) 表示只与 \(i\) 有关的,用 \(kx\) 表示两者都有关的,用 \(y\) 表示只与 \(j\) 有关的。
分析单调性: \(x\) 单调递增。
因为取 \(b\) 的最小值,且 \(k\) 为正数,故维护一个 \((i,dp_i)\) 的下凸包。可以用单调队列优化。
T3 【IOI】Wall
维护一种数据结构,支持区间取 \(\max,\min\) ,最后输出每个位置的值。
显然线段树,我们甚至不需要维护信息。
考虑两种标记 \(max\) 和 \(min\) ,注意到标记显然有先后顺序,但是当前节点受到一个新标记后,就把老标记重置为新标记。例如:原本节点上有一个 \(min=5\) ,此时下传一个 \(max=7\) ,则更新 \(min=7\) ;此时下传一个 \(max=3\) ,则无需更新 \(min\) 。若此时下传一个 \(min=3\) ,则更新 \(min=3\) ,若下传 \(min=7\) ,则不用更新 \(min\) 。
T4 控制
有 \(n\) 类装备,每种类型有 \(m_i\) 种,且各有一个魔力值,定义一个方案为每一类选一个;你要求出前 \(k\) 大方案的魔力值总和。
套路题,优秀的暴力是 用优先队列维护,类似搜索,从一个状态向外转移,并加入堆里。为了避免加重,需要加入顺序的约定。
正解比较复杂,但发现本质和 \(dij\) 很像,所以可以转换成图论,建立 \(nm\) 个点,每个第 \(i\) 类的点,向每个第 \(i+1\) 类的点连边。直接可并堆优化 k 短路即可。需要虚拟源点和汇点。
Nfls 10.14
T1 超速
出题人没码,二分答案题少打了一句话:最大值最小。
T2
给定序列 \(a_i\) ,定义一段区间的价值是这段区间不同数的个数,定义 \(S_i\) 为整个序列所有长度为 \(i\) 的区间价值的和。
你要求出每个 \(S_i\) 。\(n\le1e5\) 。
记 \(pre_i\) 为 \(a_i\) 上一个出现的位置, \(nxt_i\) 为 \(a_i\) 下一个出现的位置。
考虑贡献,\(a_i\) 作为这个区间第一个出现的,枚举 \(i\) 左边选了 $[0,i-pre_i+1] $ 个,右边选了 \([0,n-i+1]\) 个,记两边选择之和为 \(sum\),\(a_i\) 对 \(S_{sum}\) 有 贡献 。若 \(sum\le \min(i-pre_i+1,n-i+1)\times 2\) ,是一个区间加等差数列的形式,其中首项为1,公差为1。否则,对于 \(sum\in [\min(i-pre_i+1,n-i+1)\times 2,\min(i-pre_i+1,n-i+1)+\max(i-pre_i+1,n-i+1)]\),也就是一边会多出来的部分,是区间加常数。
区间加等差数列(一次函数)怎么做?等差数列本质是差分数组的区间修改,于是我们可以差分 差分数组做到 \(O(n)\) ,也可以套一个线段树支持区间修改,区间前缀和 ,复杂度 $O(n \log n) $。毕竟询问是最后一块询问,选择哪一种方法都可以通过本题。复杂度瓶颈在 map
记录 pre
。
讲一下二维差分是怎么做的。
上面说的有点麻烦了,实际上代码很简单。
for (int i = 1; i <= n; i++) {
int A;
cin >> A;
int x = i - p[A];
int y = n - i + 1;
if (x > y)
swap(x, y);
sum[1]++, sum[x + 1]--, sum[y + 1]--, sum[x + y + 1]++;
p[A] = i;
}
for (int i = 1; i <= n; i++) sum[i] += sum[i - 1];
for (int i = 1; i <= n; i++) sum[i] += sum[i - 1];
for (int i = 1; i <= n; i++) cout << sum[i] << " ";
T3 ROIR 海报
\(n\) 个人围成一圈,每个人有一个美观值 \(w_i\) ,你要选出其中若干个人,不能选择连续超过 \(4\) 个人。使得美观值最大。
同时有 \(q\) 次修改某个人的 \(w_i\) ,你需要对每次修改后询问最大美观值。
序列上的【动态dp】 板子题。用广义矩阵乘法和线段树来维护带修改的 dp 方程。 \(dp_{i,j}\) 表示以 \(i\) 结尾,最后选了 \(j\) 个人的最大美观值。
无修改时,方程比较简单: $dp_{i,0}=\max {j=0,1,2,3} dp $ ;\(dp_{i,j}=dp_{i-1,j-1}+a_i,j\in[1,3]\) 。
因为是环,终点和起点也要满足不能连续超过4个人,比较无脑的方式是断环成链,不同起点要跑四遍线段树。但是下文对此情况有巧妙的避免方式。
对于带 $\max $ 的方程,我们一般需要广义矩阵乘法 \(A*B=C\) ,其中 \(C_{i,j}= \max_{k=1} (A_{i,k}+B_{k,j})\) 。
至于这样做的可行性,关键在于矩阵乘法仍然满足结合律和分配率,即内层运算对外层有分配率。回顾普通矩阵乘法,加法对乘法有分配率;广义矩阵乘法中,
max
对+
也有分配率。即max(a,b)+c=max(a+c,b+c)
。
将转移方程写成矩阵的形式:
又因为有结合律,所以
因为带修改,用线段树维护 \(\prod B_i\) ,每次修改都是一次线段树单点修改矩阵,每次询问直接用根节点即可。
如何避免建四棵线段树呢?因为是个环,所以初始矩阵 \(A\) 中 \(dp_{0,j}\) 就是答案矩阵中的 \(dp_{n,j}\) 。我们直接讨论以 \(n\) 结尾选了 \(j\) 个,初始矩阵除了 \(dp_{0,j}=0\) ,其他都是 \(-\infty\) ,此时答案矩阵只能选 \(dp_{n,j}\) 。而对应在中间的转移矩阵,就是第 \(j\) 行,第 \(j\) 列的元素。所以在代码实现中,不需要维护初始矩阵和答案矩阵,最后只需统计线段树根节点矩阵对角线的最值即可。
代码实现上有一些技巧,例如可以通过重载一维运算符而实现重载两维运算符,涉及内存访问的一些知识。注意开 long long
。
Luogu csp 模拟赛 10.15
T2
Nfls 10.16
T1 魔力子串
给定一段字符串,设字符串中的不同字符数量为 \(k\) ,定义一个有魔法的子串,满足子串中不同的字符数为 \(k\) ,且每个字符的出现次数都相同。
csp预告题。
发现就是等价于 子串 内所有字符都有,且数量相同。肯定要用桶来统计,记 \(cnt_{c,i}\) 表示 字符 \(c\) 在前 \(i\) 位出现了多少次,一个子串合法,等价于 $\forall c,cnt_{c,r}-cnt_{c,l},= cnt_{c',r}-cnt_{c',l} $ 。(先考虑只有两种字符的情况)这样等号一侧不好处理,我们移项可以得到: \(cnt_{c,r}-cnt_{c',r}=cnt_{c,l}-cnt_{c',l}\) 。 (对于更多字符的情况)这样我们每个位置有一个长度为 \(\sum\) 的数组,对于字符串子串数量问题很容易转换成这样,然后哈希+ map
处理。 ——csp-s2023T2
。
另外值得一提的是,vector
自带比较符,但是比较是线性的哦,不过这道题 vector
长度只有 26
。
在 u群里学到了用线段树维护 hash
的 \(O(\log)\) 复杂度方法。感觉可以一学。
T2 吃树
给定一棵树,求将其分为任意多个大小相同的连通块,有多少种分法。 \(n\le1e6\)
猜结论题。
如果每个块大小都是 \(2\) ,那么一棵有两个儿子,三个节点的子树显然是非法的。
整棵树能分成大小为 \(x\) 的连通块,首先需要 \(x\mid n\) 。其次你要有 \(\frac{n}{x}\) 棵子树的大小要是 \(x\) 的倍数。
所以枚举 \(n\) 的因数,\(O(n)\) 检查,复杂度 \(O(d(n)\times n)\) 。\(d(10^6)\) 大约为 \(240\) 。
T3 弹弹床
有 \(n\) 个弹弹床,每个有属性 \(c=L\) 或 \(R\) ,代表其下一步能跳到所有在左边/右边的弹弹床,问从任意一个点开始游戏,有多少种方案,能够跳 \(n\) 张床恰好一次,且 最后一步停在 \(i\) 。\(n\le5000\)
神仙dp题。将路径拆成子路径而便于转移
一档部分分是 \(c_n=R\) ,考虑这个怎么做?
意思就是弹到 \(n\) 后再也出不去了,所以有且仅有 \(i=n\) 时有答案,其它都是 \(0\) 。
分析一下弹到 \(n\) 的过程,最后一步一定是向右到 \(n\) ,中间会向右,向左,(我们把相邻两个向右操作看作一次向右),更进一步,我们可以化简一次操作为:(向左)+向右,即可能没有向左,但最后一定向右。
例如 RRLRLR
路径可以为 \(4\to 5\to2\to3\to1\to6\) 可以拆成 \(4\) ,\(5\to 2\) ,\(3\to 1\to 6\) 三条子路径。
考虑 \(dp\),设 \(dp_{i,j}\) 表示前 \(i\) 个点,形成了 \(j\) 条最后向右的子路径 的方案数。
然后我们从左向右枚举,遇到一个 \(c_i=R\) ,则可以作为新的一条路径的开头,也可以作为之前的一条路径的结尾,如果遇到一个 \(c_i=L\) ,则可以作为之前的一条路径的开头,也可以合并两个路径 。
转移:
最后答案即 \(f_{n,1}\) 。
对于一般的情况
还是用 路径合并 的思想,我们求出最后一步向右的 \(f_{i,j}\) 和最后一步向左的 \(g_{i,j}\) 。对于当前点 \(i\) 的答案路径,一定是 左边最后一步指向右,右边最后一步指向左,如此循环。我们只需考虑答案怎么拼接。无非 LRL,RLR,LRLR,RLRL
, 这样四种情况。
LRL
\(f_{i-1,j} \times g_{i+1,j+1}\times j\ ! \times (j-1)\ !\)RLR
\(f_{i-1,j+1} \times g_{i+1,j} \times j\ ! \times (j-1) \ !\)LRLR
+RLRL
:\(f_{i-1,j}\times g_{i+1,j} \times j\ ! ^2\times 2\)
Nfls 10.17
T1 子段排序
给定两个数组 \(a_i\) ,\(b_i\) 。你可以进行若干次操作,每次选择 \(a\) 中任意一段 \([l,r]\) ,并排序,问是否能将 \(a\) 变成 \(b\) ,如果能,需要构造一组操作序列。要求操作数不超过 \(n^2\) 。
如果非法,的条件是什么? (CF1187D) :即 \(b\) 中出现 \(a\) 没有出现的逆序对。如果合法,一次排序至少减少一个逆序对,而逆序对的个数是 \(n^2\) 的。我们可以采用最暴力的方法,即冒泡排序:每次交换相邻两个。不断冒泡,直到两个全部相等。
T2 伪快速排序
你要执行如下的快速排序。
int partition(int l, int r){//这部分和快排相同 int x = a[r]; int i = l; for(int j=l;j<r;j++){ if(a[j] < x){ swap(a[i], a[j]); ++i; } } swap(a[i], a[r]); return i; } void Qsort(int l, int r, int h){ if(l<r && h>1){ int m = partition(l,r); Qsort(l,m-1,h-1); Qsort(m+1,r,h-1); } }
你想知道有多少个排列 \(a_i\) 满足在给定 \(k\) 的情况下,能变成有序数组。
快排的基本思想就是每次钦定一个标准,把小于标准的都扔前面,大于标准的都扔后面,递归实现。
但是 正常的快排,递归的深度是 \(\log\) 层,怎么考虑在 \(k\) 层递归。
当 \(k=2\) 时,只进行一次,需要 \(a_i<a_n\) 的部分在原序列是有序的,\(a_i>a_n\) 的部分在原序列也是有序的。枚举 \(a_n=i\) ,就是把 \([1,i-1]\) 的有序排列和 \(i+1,n\) 的正序排列插空变成一个。也就是说,一次 partition
的本质是将两个有序数组合并成一个有序数组,否则仍然是无序数组,返回的是 \(<a_n\) 的个数。
排列方案考虑 dp
,设 \(dp_{i,j}\) 表示长度为 \(i\) ,进行 \(j\) 次递归后,数组有序的方案。
枚举 小于 \(a_n\) 的个数 \(k\) ,则有转移:
组合数的意义是 选择 \(k-1\) 个数放在前面作为一个有序数列。
T3 二进制式
给定一个二进制表示串,例如
((x^x)|(x&x))
,其中包含 \(n\) 个变量 \(x_i\) ,对于每一个 \(x_i\) ,你要输出:当除 \(x\) 外其他 \(n-1\) 个变量固定时,\(x\) 取 \(0\) 和 \(1\) ,最终表达式的值不同的概率。 \(n\le10^5\) 。例如
x or y
:固定 \(y=1\) 的情况下,\(x=0\) 和 \(1\) 没有区别,固定 \(y=0\) 的情况下,\(x=0\) 是 \(0\) ,否则是 \(1\) 。所以概率是 \(\frac{1}{2}\) 。
这种确定总数:\(2^{n-1}\) 的概率问题,直接统计 分子即可。带着分母求就又是逆元又是什么,非常难算。
首先我们不难将这个字符串通过 栈 维护出一棵前缀表达式二叉树。其中 非叶子节点都是 符号,叶子节点是 \(x\) 。但是注意 字符串的大小是 \(n\) 的 \(4\) 倍以上。(挂40)
接下来肯定是要树上 \(dp\) ,\(n^2\) 的暴力做法就是每次固定一个数,然后做一遍 dp
。\(f_{u,0/1}\) 表示 \(u\) 节点答案为 \(0/1\) 的方案数。
例如:当 op='^'
时,\(f_{u,0}=f_{ls,1}\times f_{rs,0}+f_{rs,1}\times f_{ls,0}\) 。
考虑正解:对于一次修改,影响到的点就是从 \(u\) 到 \(1\) 这条链上。于是我们再开一个 \(g_{u}\) 表示 \(u\) 子树内有固定,整个子树外,使得答案不同的方案数 。
这里跳出常规 $dp $ 模式了
\(g_{ls}=g_u\times f_{rs,x}\) 其中 \(x\) 在符号不同时不同。例如 或运算:需要 \(f_{rs,0}\) 。因为原本不同 或 0 还是不同,原本不同 或 1 就都相同了。
答案即 $g_i $ 。
Nfls 10.18
T1 玛雅历
日期型大模拟,可以采用公元前暴力做,公元后,400年的周期直接统计,剩下的散块暴力做。
T2 大融合
简化并省略简单部分:
给定一个 \(n*n\) 的棋盘,点有分数值和颜色,如果上一步和当前颜色相同,额外获得 \(1\) 分,你可以设置 \(g\) ,跳跃距离为 \([max(1,d-g),d+g]\) ,只能往下往右。求获得 \(s\) 分数的最小 \(g\) 。
外层直接二分,怎么用单调队列优化这个东西。
对于二维上的问题,我们只需要每一行,每一列,都维护一个单调队列即可,两者之间取 \(max\) 。
对于有颜色的问题,因为这道题颜色数比较少,可以每一行,每一列 的每一种颜色建单调队列。如果颜色多了,一个套路是把颜色都扔进 set
里,即每一行,每一列,开 \(n+m\) 个 set
,set
里的元素是单调队列。找到时间空间的平衡。
T3 好 ♂ 朋 ♂ 友
给定一个序列 \(a_i\) ,和集合 \(S\) ,并有若干次询问 \([l,r]\) ,每次询问区间内有多少子区间,满足子区间的或和,的个位数为 \(s \in S\) 。
经典套路题,离线后固定左端点,只有 \(O(\log W)\) 个关键点会影响,快速找出这些点。只需要找 \(a_l\) 的二进制表示中,为 \(0\) 的位上,后面第一个该位为 \(1\) 的位置。二进制拆位后可以二分。
得到这些 关键点后,直接暴力找出 满足 的位置区间,例如 $[key_i,key_{i+1}-1] $ ,然后对这些区间+1。如果我们倒序枚举询问,即从右往左加,那么当前 \([l,r]\) 的询问就是 该区间的区间和。好神奇。不用写区间历史和了。还是说根本不是一回事呀。
胜利一中SD联测2 10.18
T1 谁共一杯方酒
给定 \(n\) 个区间,求最多多少个区间满足 \(\forall\ i\) 被 \(i+1\) 包含。
按右端点排序后,等价于左端点的最长上升子序列。
线段树大常数选手+dwt没开O2 \(\to\) \(90 pts\) 。
T2 约会
给定一棵树,边有方向且有边权,你可以通过 \(1\) 的代价改变某个点的方向,你需要选择一个点 \(x\),使得最远的点到 \(x\) 的距离不超过 \(D\) ,且满足代价最小。求代价。
最远的点可以用树的直径求,距离直接带 \(\log\) 差分。
代价稍微推一下,等价于:子树内的下边+ \(1\) 到 \(x\) 链上的上边+除两者外的下边。
T3 乱杀
有两个人在数轴上,给定若干个限制:需要在 \(t_i\) 时刻至少有一个人在 \(x_i\) 位置上,求两个人的最大速度最小是多少。
-
考虑 \(n^2\) \(dp\) 做法:
和 bct暑假集训某一天的 \(T4\) 非常像,关键在于 两个人的位置,其中一个人一定在 \(x_i\) 上,那道题我们 \(dp\) 另一维存另一个人的位置,这里有些难办了,因为位置可能是实数,所以我们可以存 另一个人上次击球的时刻,位置即 \(x_j\) ,因为我们知道 一个人两次击球之间是会往返的。这样存就一定是整数了。转移依旧是经典的 \(n*O(1)+O(n)*1\) 的形式。
-
\(n \log n\) 二分答案:
与那一题不同的是,\(dp\) 式子是中有若干 \(\min 和 \max\) ,数据结构难以维护。考虑二分答案。(和 \(dp\) 已经完全没关系了)
赛时也想到了,我们知道其中一个人 \(P\) 的位置 \(a_i\) ,另一个人 \(Q\) 的位置一定是一个区间的的形式,设该区间为 \([L,R]\) ,二分答案速度为 \(V\) ,在 \(\Delta T\) 的时间内最多可以走 \(S=V\Delta T\) 的路程。则 \(P\) 下一步可以走到 \([a_i-S,a_i+S]\) ,\(Q\) 下一步 可以走到 \([L-S,R+S]\) 。
-
如果这两个区间都到不了 \(a_{i+1}\) ,那么说明无解。
-
如果 \(P\) 能够到达,\(Q\) 不能到达。那么 \(P\) 下一步去找 \(a_{i+1}\) ,\(Q\) 下一步的区间再各左右扩展 \(\Delta S\) 。
-
如果 \(Q\) 能到达, \(P\) 不能到达,两者身份互换。
-
如果两者都能到达,那么 \(L\) 和 \(R\) 的取值对上述情况取最值即可。
为什么是对的?此时另一个人处于两个人的叠加态,进行下一步时,我们实际会用到谁,那个人就是谁,因为两者都可以用,而且我们不关心他们到底是谁。
感觉是有点神仙的贪心。
-
T4 红藕香残
给定一个序列 \(a_i\) ,和常数 \(k\)。多次询问给定一个区间 \([l,r]\) ,删掉 \(k\) 个数后,区间 \(\gcd\) 最大是多少?注意 \(k\le3\) 。
-
首先考虑 \(k=0\) 。
st表。但正解肯定很难从这上面想,注意到 \(\gcd\) 和 \(|,\&\) 类似,固定左端点后只会变化 \(\log\) 次,因为每次变化至少除以二。因此我们还是找所谓关键点。
那么我们从左到右枚举右端点。记二元组 \((l,v)\) 表示每个关键点的位置,以及每个关键点的一个后缀 \(\gcd\) ,即 \([l,r]\) 。初始只有 \((1,a_1)\) 。
然后考虑右端点扩展,之前是关键点的有可能还是关键点,之前不是关键点的一定不会是新的关键点 。具体的,我们新加入一个关键点 \((r,a_r)\) ,然后更新关键点 (不超过 \(\log\) 个)的 \((l,v)=(l,\gcd(v,a_r))\) 。再对所有 \(v\) 相同的,只保留从右向左第一个即可。
对于询问,我们直接找右端点为 \(r\) ,左端点最小的一个 \(l\) 的 \(v\) 即可。复杂度 \(O(n\log n)\) 。
-
考虑 \(k=1\) ,我们要删除一个数。可以肯定的是我们一定会删关键点,否则对答案是没有贡献的。于是枚举 以 \(r\) 为右端点的 \(\log\) 个关键点( \((r,a_r)\) 算作一种关键点,不需额外考虑)。枚举删的点后还要加上找左端点,然后求两者 \(\gcd\) 。复杂度 \(O(\log^2)\) 。
-
对于 \(k>1\) 的情况,直接 暴力dfs枚举删点位置,暴力做就行,常数极小,1e5 \(O(n\log^4)\) 可以通过??? 。
卡常题了属于是。
[不过调了大约2h,怎么回事呢?](记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)) 一开始我在 dfs
的时候是类似 dp
的, ans=max(ans,gcd(dfs(l,y-1,k-1),query(y+1,r)));
但实际上这肯定不满足dp,是直接把所有情况枚举出来统一处理。如下
void dfs(int l,int r,int R,int k,vector<int>v) {
if(k==0) {
int ll=l,sum=0;
for(int i=v.size()-1;i>=0;i--) {
int y=v[i];
sum=gcd(sum,query(ll,y-1));
ll=y+1;
}
sum=gcd(sum,query(ll,R));
ans=max(ans,sum);
return ;
}
vector<int>t=v;
for(int i=s[r].size()-1;i>=0;i--) {
int y=s[r][i].l;
if(y<l) return ;
t.push_back(y);
dfs(l,y-1,R,k-1,t);
t.pop_back();
}
}
还有若干细节,例如我是用右端点,所以遍历 vector
都要倒序枚举。
CSP-S 2023
T1 [CSP-S 2023] 密码锁
简单模拟,不过大样例想了挺久。
T2 [CSP-S 2023] 消消乐
给定一个字符串,求有多少个子串满足可被消除。一个子串可被消除的定义是:任意两个相同的字符可以拼起来,然后消去,最后消完。
考前刚做过 hash
统计字符串的题,没想起来,寄。
\(n^2\) 暴力用栈维护即可,一个子串合法 当且仅当栈被消除至空 类似括号匹配。
根据栈的启发,一个常见的 trick 是将区间为 \(0\) 转换成前缀相等来统计。用 哈希维护一个栈,\(O(n)\) 求出一遍前缀 哈希栈。对于一个栈的状态,哈希值为 \(s\) ,用一个 map
维护之前有多少个 s
。答案累加 map[s]
即可。
如果我们不用 hash
,也可以考虑 dp
,\(dp_i\) 表示以 \(i\) 为右端点的答案,怎么转移? 使用 \(pre_i\) 转移比较困难,因为不能保证 \([pre_i+1,i-1]\) 是合法括号串。我们要想转移肯定是从第一个 位置 \(x\) 满足 \(x+1,i-1\) 是合法串,发现字符集较小,只有 \(26\) 。不妨记 \(g_{i,c}\) 表示 \(i\) 往前第一个位置 \(x\) ,满足 \(s_{x}=c\) 且 \([x+1,i]\) 为合法串。转移就从 \(g_{i-1,s_i}\) 转移。更新 \(g_{i,c}\) :若 \(s_i=s_{i-1}\) ,则 $g_{i,s_{i-2}}=i-2 $ 。否则,记 \(t=g_{i-1,c}\) ,所有 \(g_{i,c}\) 都从 \(g_{t-1,c}\) 转移而来。
T4 种树
Nfls 10.23
T2 括号
给定若干次操作,每次往字符串的后面加入 \(c_i\) 个左括号或者右括号,问最终有多少合法括号序列。
回顾括号序列的经典套路,要么卡特兰数,要么看作区间dp,要么分别看作 +1
,-1
。对于在序列上且给定的问题,常常想第三种方法。
如果是 \(c_i=1\) 的情况,回顾一下:
也就是 \([l,r]\) 合法的充要条件是 \(cnt_{l-1}=cnt_r,\ \forall \ x,cnt_x\ge cnt_r\) 。
也就是一个很类似单调栈的东西,维护左端点,每次加入 \(cnt_r\) ,将所有大于 \(cnt_r\) 的都弹出,然后统计的就是 \(cnt_l=cnt_r\) 的贡献。时间复杂度 \(O(n*c_i)\) 。
推广到更一般的做法,我们维护一个栈存两种值:左括号连续段的长度,以及 拼成的合法括号串数量。这样一个右括号连续段过来消,把一串左括号消完,再加上这个数字,再消,再加。
T3 学校
求 \(a\) 有多少子序列 \(p\) 满足,\(p\) 中任意四个相邻元素的异或和不为 \(S\) 。其中 \(a_i\) 互不相同。
最朴素的 \(dp\) 是记录后三位分别是什么。\(O(n^4)\) 。
也就是 \(f(i,j,k)\to f(j,k,l)\) 。但是显然 我们可以算出来不合法的一些 \(i=S\oplus l.j.k\) 。
于是 \(f(*,j,k)-f(i,j,k)\to f(j,k,l)\) 。其中 \((*)\) 代表任何数。又因为 \(a_i\) 互异,所以可以做到 \(O(n^3)\) .
具体的,
从四次方优化到平方,先优化转移,再缩减状态,再观察性质,最后优化转移。
Nfls 10.24
T2 K近查询
给定 \(n,m\) 。你需要对 \(\forall \ i\le n ,k \le m\) ,求出 \(i\) 前面 第 \(k\) 个 大于 \(a_i\) 的位置。(从后往前数) \(nk\le 10^7,k\le 5\) 。
T3 树上流水
给出一棵树,边有容量限制,\(1\) 号点作为根不断往外流水,1s 水只能移动一条边。求 使得所有叶子的水量 \(\ge k\) 的最短时间。\(n\le 1000,T\le 5\)
这样有先后顺序的树上问题一般是 贪心或者 \(dp\) 。
贪心解法
我们会尽可能希望 水先留到深度浅的叶子上,而且我们只会给这些叶子分配 它到根 路径上容量最小值,这么些水。
既然这样,我们将所有叶子按照深度排序,如果最小值非 \(0\) 的话,我们每次减去这条链的最小值,可以用树剖维护。最后,模拟一下叶子 接水的过程即可。总水量 \(\ge k\) 就跳出。复杂度 \(O(n \log^2 n)\)
dp解法
最主要的问题是不知道水往那边流,可以倒过来想,每个叶子都有水,问多久能让 \(1\) 的水量到达 \(k\) 。两者是等价的。
直接 \(n^2 \ dp\) ,设 \(dp_{u,j}\) 表示 $ u $ 号点在 \(j\) 时刻能有多少水。转移有 \(dp_{u,j}=\sum \min(dp_{v,j-1},w)\) 。可以暴力做,也可以 线段树合并加 Seg-beats。 复杂度少一个 \(\log\) 。
注意要开 long long
。
T4 逆序对
给定序列 \(a_i\) ,满足 \(n=2^k\) 。\(m\) 次询问,每次给出参数 \(p,l,r\) 。表示将 序列分成 \(2^p\) 段后,第 \(l\) 段到第 \(r\) 段,每段内部区间翻转,求操作后原序列有多少逆序对。 \(n\le 2^{20}\) 。 注意操作之间不相互独立。
一眼看上去就是自然的线段树结构,首先考虑 \(l=r\) 的情况:
将序列分块后,每次询问一个块,那么在线段树上一定能找到唯一的一段区间。我们需要给他打上一个翻转 \(tag\) ,意味着 他整个子树都需要不停交换左右儿子,直到叶子,这是标记对标记的下放。翻转这个节点,其逆序对数量变换为原先的正序对数量,这是标记对信息的影响。父节点逆序对数量等于左儿子逆序对数量,加右儿子逆序对数量,再加横跨中间,的逆序对数量(类似 cdq
分治),这是信息的合并。
建树过程可以和归并排序天然结合。维护区间逆序对 和 跨过中点的逆序对。
对于 \(l\ne r\) 的情况,问题可以转换成: 修改 $\log $ 个区间,查询 $\log $ 个区间。
Nfls 10.26
T2 树上删边
给定一棵树,点有点权,删一条边的代价是两边子树的权值最大值之和。求删完全部的最小代价。
每次贪心从最大点开始删。但是删边不好维护最大值。删边变成加边,从最小边开始加。并查集维护即可。
T3 欧几里得
定义 \(R(a,b)=R(\lfloor{\frac{a}{b}}\rfloor,b)\) 。\(T\) 次询问,每次给出 \(h,g\) 。构造一组 \(a,b\) 满足 \(R(a,b)=h,\gcd(a,b)=g\) 。
\(h,g\le 10^5\) 。
打表没啥规律,分析 \(R\) 的性质。
若 \(R(a,b)=h\) ,则一直递归到底层,有 \(R(h,1)=h\) ,同时, \(R(h,h+k)=h\) ,其中 \(k<h\) 。对于这种形式,可以继续套下去:即 \(R(h,h(h+k_1)+k_2)=h\) ;也就是说,\(b\) 可以写成 \(h(h(...+k_3)+k_2)+k_1\) ,就是一个 \(h\) 进制数的形式。
所以我们可以构造 \(r(h,b)=h\) 。只需满足 \(b\) 在 \(h\) 进制表示下,最高位是 \(1\) ,因为初始是 \(1\) 。我们希望找到一个足够大的 \(b\) 满足 \(b\) 是 \(g\) 的倍数。因为此时我们可以将 $r(h,b) $ 替换为 \(r(bh,b)\) ,此时 \(\gcd(bh,b)\) 是 \(g\) 的倍数,但不一定等于 \(g\) 。考虑构造为 \(r(bh+g,b)\) ,要注意此时 \(g<b\) 。故要特判 \(b=g\) 的情况。此时 $\gcd(bh+g,b) $恰好为 \(g\) 。
因为 \(b=kg,bh=kgh,bh+g=kgh+g=g(kh+1)\) 。\(\gcd(g(kh+1),gk)=g\) ,因为 \(\gcd(kh+1,k)=0\) 。——相邻两个正整数互质。
所以构造方案有了,我们只需要找 \(b\) ,最高位是 \(1\) ,也就是 \(b=h^k+c\) ,且要满足 \(b\mod r=0\) ,因为 \(r\) 只有 \(1e5\) ,我们随便找一个比较大的 \(k\) ,使得 \(b>1e5\) ,然后再求出 \(c\) 即可 \(O(1)\) 做完。
T4 [没有上司的涨薪舞会
给定 \(n\) 个人组成的树形结构的关系网,有些员工要求涨薪资,有些员工则不想,现在他们去参加舞会,一个人选择去参加舞会,当且仅当:
- 没有一个直接下属参加舞会,则 \(i\) 有 \(p_i\) 的概率参加。
- 否则不会选择参加。
每个员工可以选择给自己的所有下属加薪,\(u\) 能给 \(v\) 加 \(a_u\) 的薪,当且仅当 \(u,v\) 全部到场,且 \(v\) 想要涨薪资。但是 \(a_u\) 有可能是负数,即降薪。
你需要分配每个人是想涨薪资还是 不想。求最大期望薪资是多少。
根据期望的线性性,答案即为:
拆一下式子,便于统计:
其中 \(P(y)\) 的取值,并非原本的 \(P(y)\) ,而是在确定 \(x\) 参加舞会的条件下的 \(P'(y)\) 。这也是为什么统计祖先而非子树的原因。在求 \(P(y)\) 时,我们只需强制让 \(P'(x)=1\) ,即可按照 \(dp\) 方程求出。\(P(x)=\prod (1-P_{son_x})\times p_x\) 。直接暴力做复杂度是 \(O(nd)\) 的,其中 \(d\) 是整棵树的深度。
因为一次只会更新一个点,\(P'(fa)= P(fa)\times \frac{1-P'(son_x)}{1-P(son_x)}\) ,令 $v=\frac{P(fa)}{1-P(son_x)} $ ,因为 \(P\) 已经预处理好了,所以 \(v\) 是常数,而 \(P'(fa)=v-vP'(son)\) 。是 关于 \(P'(x)\) 和 \(1\) 的线性变换,具体的:构造向量 \(\begin{bmatrix}1&f_u& sum_u\end{bmatrix}\) ,其中 \(f_u\) 即 被固定后的
Nfls 10.27
T2 完美主义
给定初始字符串的长度 \(x\) ,有以下四种操作
- 末尾加一个字符,代价 1
- 全选,代价2
- 复制,代价2
- 粘贴,代价2
- 退格,代价 1
求使字符串长度变为 \(y\) 的最少代价。
可以抽象成图论问题,并且如果初始长度比较大的话,一定是复制再粘贴,否则先打几个字符再复制,问题是复制完后,是粘贴若干次(这样中间不用选中再复制了),再复制,再粘贴一个长度更长的。发现粘贴若干次不会太多,最多也就16次左右。直接暴力建图。另外最短路长度是 \(O(n)\) 的,可以桶优化 Dij。
T3 挑战哈密顿 P6644 [CCO2020] Travelling Salesperson
给定一张完全图,边有
Red,Blue
两种颜色,对于每个起点,求一条最短的哈密顿路使得每个点都至少经过一次,且经过边的颜色方案中,颜色只能变换一次,即RRRR...RRRBBBB...BBB
或先B
后R
。 你需要输出构造出的路径。
结合链表的构造好题,结论是最短路一定可以做到长度为 \(n\) 。
对于当前起点 \(u\) ,已经构造好一条 合法的链,链的末尾是 \(y\) 。设当前插入的点是 \(v\) ,分类讨论。
-
整条链只有一种颜色:
如果 \((y,v)\) 颜色相同,那么直接插入到末尾即可。
否则, \(v\) 是整条路径的颜色分界点。也插入到末尾。
-
整条链已经有两种颜色:
如果 \((y,v)\) 能直接插后面,就插后面。
否则,设颜色分界点为 \(k\) ,不妨令前半段颜色为
R
,后半段颜色为B
。- 若 \((k,v)\) 颜色为
R
,则 \(v\) 插入到 \(k\) 的后面,\(v\) 成为新的分界点。 - 否则,将 \(v\) 插入到 \(k\) 的前面,\(v\) 成为新的关键点。
总复杂度 \(O(n^2)\) 。
- 若 \((k,v)\) 颜色为
但是!list
有点复杂了点:一些要牢记的边界处理:
list.insert(++k,x)
后要判断 if(k==list.end()) k--
。虽然我也不知道怎么回事,但好像整体往前平移了一段?
T4 装备
给定若干个二元组 \((a_i,b_i)\) ,并保证 \(a_i\) 互不相同。你有 \(k\) 次 \(swap(a_i,b_i)\) 的机会,需要保证 \(a_i\) 时刻互不相同。你想要使得 \(a_i\) 构成序列的字典序尽可能大。输出交换序列。
本题 trick
和 联合省选2023 Day2T2 填数游戏 几乎完全一样。
根据 \(a_i\) 互不相同,我们想到树的父亲是唯一的。
对于初始给定的每一个 \((a_i,b_i)\) ,建一条 \(a_i\) 指向 \(b_i\) 的有向边。最后形成若干个弱连通分量,对于每个分量,只可能是内向树或 内向基环树。对于一棵内向基环树,没有交换的空间。对于一颗内向树,只有根节点 没有入边,而这个根节点就是我们能留出“空”来交换的位置。
具体的,合法的状态体现在:每个点最多只有 \(1\) 条入边。交换的操作体现在:将一条边反向。我们想要反向一条边,此时 一个点一定会改变入度个数,如果这个点是根的话不用管,否则入度为 \(2\) ,需要将这个点到 根的路径全部反向,以消除这个影响。然后这条边连的另一条边成为新的根。
因为我们要使得字典序尽可能大,所以从左往右枚举,每次翻转后的边就固定好了,下次不能再动了。这样均摊复杂度就是 \(O(n)\) 的。
对于操作数,我们可以 dfs
的时候统计一下就可以,如果超过 k
就跳过这一轮。
联合省选d2T2 填数游戏
Nfls 10.28 分块专题
T2 疯狂星期四
有 长度为 \(n\) 的序列 \(a_i\) ,和 \(m\) 个函数 ,每个函数 \(f(i)\) 表示 \(\sum _{j=L_i}^{R_i} a_j\) 。
- 单点修改 \(a_x\to y\)
- 区间函数和, \(\sum_l^r f(j)\) 。
\(n\le 10^5\) 。
赛时一直在想应该不可做的 \(polylog\) 做法,感觉分块再带 \(log\) 非常吓人呀。不过实际上分块加log肯定能过 \(1e5\) 的。
大概是应该不均摊的均摊线段树+二维数点、、、如果把 懒标记改成 vector
的复杂度是多少呀。
讲讲正解,对外层函数分块。
也就是分成 \(\sqrt m\) 块,每块存函数和。这样区间整块和是简单的。考虑 \(a_i\) 会对第 \(j\) 块产生多少贡献,也就是 \(a_i\) 在这个块的出现次数。可以想到差分统计次数。也就是每个函数对所在块的次数贡献是区间 \([L_i,R_i]\) 加一。最后差分数组累加可以得到第 \(i\) 个块,\(j\) 的出现次数 \(cnt_{i,j}\) ,一个块的和初始就是 \(\sum cnt_j\times a_j\) 。
那这样单点修改也可以做了,对于 \(a_x=y\) ,求出变化量 \(\delta\) ,它对所有包含它的块都有贡献,也就是 \(cnt_{i,j}\times \delta\) 。然后 \(a_x=y\) ,这一步是 \(O(1)\) 的,显得有些快了。
对于区间查询,整块和有了,散块和怎么做?即 \(\sum _j\sum _{k=L_j}^{R_j} a_k\) 。树状数组是可以做到 \(O(\sqrt n \log n)\) 。考虑怎么不用树状数组,显然这是一个前缀和。考虑根号平衡:\(O(1)\) 查询区间和,\(O(\sqrt n)\) 单点修改。也就是每个块维护 第 \(1\) 到第 \(i\) 块的前缀和,块内维护块内前缀和。对于上面的 \(O(1)\) 修改就能改成 对 \(O(\sqrt n)\) 个块进行修改。达到根号平衡的效果。
调了挺长时间,问题在于对散块的处理大概率是不对称的,不要直接复制或者比着写。
T3 一九八四
给定一个 \(n*m*h\le 10^5\) 的空间,要求支持:
- 在 \((x,y,z)\) 位置插入一个点
- 询问离 \((x,y,z)\) 距离最短的点,距离指曼哈顿距离。
So1.错解
三个数相乘的结果小于 \(10^5\) ,则中间数的大小 \(b\) 不会超过 \(\sqrt {10^5}=400\) 。将中间这一维定成枚举维,切割成若干个平面。每个平面存平面的答案。但是平面的大小并非根号级别的,反例:1 10 100000
。
Sol2.定期重构:时间分块
适用于解决:修改间相互独立 的问题。每次加入一个点,并不会对别的点产生影响。
我们设 \(ans_x\) 表示 \(x\) 点的最近距离,这样直接做,查询是 \(O(1)\) ,修改是 \(O(n)\) 。
但是我们可以每 \(\sqrt{q}\) 次修改就重构一遍 \(ans\) 。这样每次重构用洪水填充算法,将需要重构的点扔进队列。复杂度 \(O(n)\) 。每次询问,先查 \(ans\) ,再暴力枚举 \(O(\sqrt n)\) 个没有重构的点的距离。总复杂度 \(O(n\sqrt n )\) 。
T4 旅行
给定一棵树,边有边权 \(w\in [1,2]\) ,每次询问从 \((u,v)\) 这条路径,每天最多走 \(k\) 公里,晚上必须在节点留下。需要多少天可以到达。
Sol:根号分治
对于 \(k\ge \sqrt n\) 的情况,最终结果不会太多,所以二分暴力跳即可。
对于 \(k<\sqrt n\) 的情况,小块是很好做的,预处理出 \(f_{u,j,k}\) 表示 \(u\) 向上跳 \(2^j\) 天,每天最多 \(k\) 步,能到达哪个点。
时间应该够,空间可能不大够,离线下来对于 \(k\) 相同的统一处理。这样空间复杂度就只有 \(O(n\log n)\) 了。
代码实现上,注意怎么跨过 \(lca\),最后如果 \(x,y\) 都在 \(lca\) 上则不管,否则 这一段距离要么跳一段,要么跳两段。
Nfls 10.30
T2 药品实验【2019数学高考】
给定 \(n,a,b,c\) 其中 \(a+b+c=1\) ,设 \(p_i=ap_{i-1}+bp_i+cp_{i+1}\) 。已知 \(p_1=0,p_{2n}=1\) ,求 \(p_n\) 。
高考数列题,原题第一问要求证 \(\{p_i-p_{i-1}\}\) 是等比数列。
公比是 \(k=\frac{a}{c}\) 。
所以 \(\sum (p_i-p_{i-1})=p_{2n}=1\) ,其中首项 \(p_1-p_0=p_1\) 。 \(p_1\times \frac{1-k^{2n}}{1-k}=1\) ,可得 \(p_1=\frac{1-k}{1-k^{2n}}\) 。
又因为公差知道, \(p_n\) 就可以递推地算出来,当然可以矩阵加速。
T3 小猫钓鱼
\(n\) 个人打扑克,每个人初始有 \(l\) 张,类型和排火车类似,有超级派,可以把所有牌都收起来。\(n,l\le 100\) 。求 \(T\) 轮后每个人手里的牌。\(\sum T=10^6\) 。
时间复杂度计算题,模拟实现即可,需要离散化或者 unordered_map
。
复杂度 \(O(Tn)\) 为什么是对的?首先添加牌和收走牌数量的复杂度是相等的,一轮比赛只能增加 \(n\) 张牌,所以均摊会收走 \(O(n)\) 张牌。
T4 模拟旅行
给定一个集合 \(S\) 内有若干个点,求这个集合中任意两点在有向图中最短路的最小值。
kdw说是 BCT
原题,但是正好那天没讲图论,哈哈。
特殊点问题首先考虑建虚拟源点/虚树。现在考虑虚拟源点,向每个特殊点连一条边。边权为 \(0\) 。
这样可以得到所有经过至少一个关键点的最短路 \(d_u\) 。但是我们不知道经过的是哪个关键点,设 \(f_u\) 表示,最短路松弛的时候一块求就行。
Sol1 二进制分组
特别适合这样的分组问题。
作为答案的两个点的编号一定有一位二进制不同。那我们枚举二进制位,将这一位是 \(0\) 的关键点分为一个集合,为 \(1\) 的分为一个集合。连虚拟源点跑两遍最短路。枚举终点组的答案。复杂度 \(O((n+m)\log m\log k)\) 。
Sol2.反向图
考虑作为答案的两个点 \((u,v)\),他们之间的路径一定是一段经过 \(u\) 的最短路径,再接着跳到一段经过 \(v\) 的最短路径。或者说是从 \(u\) 出发走最短路,接着切换到从 \(v\) 出发的最短路。后者是反图上的。
形式化地, \(dis=d_x+w+d'_y\) ,满足 \(f_x=u,f'_y=v\) 。\((u,x),(y,v)\) 均为最短路。
时间复杂度 \(O((n+m)\log m)\)
Div1 T4 迷雾华光
在线算法求树上众数。
区间众数:蒲公英,一种简单的方法是设 \(f_{u,v}\) 表示 \([u,v]\) 块之间的区间众数是谁,\(g_{u,x}\) 表示前 \(u\) 个块内 \(x\) 出现了多少次,时间空间复杂度均为 \(O(n \sqrt n)\) 。
考虑搬到树上,随机撒关键点,对于 \((u,k_1)\to(k_1,lca)\to (lca,k2)\to (k2,v)\) 这样的路径,中间是整块,两边是散块。需要特判 \(lca\) 的情况。
Nfls 10.31
T3 小 G 的布料
给定一个 \(n*m\) 的 \(01\) 矩阵,求面积大于等于 \(k\) 的全 \(0\) 子矩阵个数。 \(n\le3000\) 。
小清新并查集线性做法
并查集算 \(O(1)\) 。
先预处理出 \(f_{i,j}\) 表示 往下有多少连续的 \(0\) 。对于每一行,我们按照矩形高度递减地加矩形,每次加一批高度相同的新的全 \(0\) 矩形都会形成一批新的矩形连通块,用并查集维护连通性,我们只需统计这些新生成的连通块。可以用 vector
记录第 \(i\) 行,高度为 \(j\) 的矩形是哪些。
考虑每次形成一个新的连通块,该连通块的左端点为 \(L\),右端点为 \(R\) ,当前高度为 \(h\) 。统计它带来的贡献,注意到此时 \(L-1\),\(R+1\) 处的矩形都没有添加进来,为了保证不重不漏,我们只统计高度 \(k\in[\max(f_{i,L-1},f_{i,R+1})+1,h]\) ,宽度 \(w\in[1,R-L+1]\) 的合法矩形数量。这个东西提前预处理前缀和即可。
T4 Easy Data Structure
给定一二进制表达式树,包含三种基本二元运算操作,每个叶子有 \(p\) 的概率是 \(1\) ,\(1-p\) 的概率是 \(0\),求根为 \(1\) 的概率。支持修改叶子的概率。
树上动态dp,基本思想是树剖后,每个节点的矩阵表示的是,其重儿子为 \(0/1\) 时,自己为 \(0/1\) 的概率,即一个 \(2*2\) 的矩阵。每次修改,先修改这个点,再修改这个点到链顶,可以线段树做,然后跳一条轻边。。。以后再来学习吧。
Pyyz 11.2 Day1 by ZYW
T1 矩阵优化
T2 字符串
定义一个长度为 \(n\) 的字符串的价值是:这个字符串所有长度小于等于 \(\frac{n}{2}\) 的 border 的长度之和。
求给定字符串所有子序列的 border 价值之和。 \(n\le300\) 。
暴力非多项式复杂度的,有关子序列的, 考虑 dp,设 \(dp[i][x][y]\) 表示 border 长度为 \(i\) 的子序列,前半段结尾于 \(x\) ,后半段结尾于 \(y\) 。有转移:
$dp[i][x][y]=\sum dp[i-1][x'][y'] $ ,满足 \(s[x]=s[y]\) 。答案就是 \(\sum_i\sum _p dp[i][x][y]\times i \times 2^{p-x+1}\) 。其中 \(p\) 是枚举的后半段开头的位置,需要满足 \(x\le p\) 。
转移的式子不难可以前缀和优化。
这样做枚举答案复杂度是 \(n^4\) 的,发现我们不需要记录 \(i\) 这一维。可以用 \(g[x][y]\) 表示这样的 \(f[x][y]\) 的 \(\sum i\) 是多少,本质仍是乘法对加法有分配率。
\(g[x][y]=\sum g[x'][y']+f[x][y]\) 。答案是 \(\sum f[x][y]\times g[x][y]\times 2^{p-x+1}\) 。复杂度为 \(O(n^3)\) 。
T3 通讯公司
有 \(n\) 个人 ,\(m\) 个通讯公司,每个通讯公司包含若干人(用集合 \(S_i\) 表示),同一通讯公司下的用户可以互相拨号,一个人最多可以向一个人发出拨号,但可以同时收到多个人的拨号。 \(x\) 向 \(y\) 拨号的收益为 \(a_x\times a_y\) ,但是两个人互相拨号的收益仍然是 一倍。求某一时刻总收益最大是多少。
\(n\le 10^5,\sum |s_i| \le 10^5\) 。
我完全不会 最小生成树。
考场上一直在模仿【省选D2T2 填数游戏】的 trick 去搞 内向基环树的换根,但这样是完全没有必要的,因为我们毫不关心基环树边的方向,也就是当成无向图看就行,一直没想到点权转边权,直接暴力建图,将一条边 看做 \(a_x\times a_y\) ,做最大基环树即可,实现和 kruskal 基本一样 ,最多一个环。
但这样做复杂度太大了,建图的复杂度就是 \(O(\sum |s_i|^2)\) 的。我们观察加入到最大生成树的边,一定是一个集合内,最大点所连出的边,和次大点所连出的边,因为这些边就足以构成一棵基环树了。
T4 dp of dp
害怕。别考。
Day2 by ZYW
T1 小数点
给定一个分数 \(p,q\),求 \(\frac{p}{q}\) 的第 \([l,r]\) 位。\(l,r\le 10^9,r-l\le 10^5\) 。
好题,考场上想了半小时的数论意义,发现小数循环节的长度 \(len\) 是最小的满足 \(10^{len}=1\mod q,q\ne2k,5k\) 的正整数,然后 BSGS?NOI Plus模拟赛。
但实际上根本没有这么麻烦,问题关键在于快速幂不能取模,先把式子写出来:
$ \lfloor \frac{10^Lp}{q}\rfloor \bmod 10 \Longleftrightarrow \lfloor\frac{10^Lp-10q}{q}\rfloor \bmod 10\Longleftrightarrow \lfloor\frac{10^p\bmod 10q}{q}\rfloor \bmod 10$ 。这样就能取模了
启示:对于在数论模意义下难以解决的运算,例如向下取整等,可以考虑其等价的效果,也就是减去一个数,仍然相等,相当于对这个数取模。
另外,别遇到小数题就想你那模意义了。
T2 体力劳动
给定序列 \(a_i\) 和 \(x\) ,求一个最小区间长度 \([l,r]\) ,满足区间逆序对个数 \(\ge x\) 。
区间长度有单调性,相当于二分答案。然后 check 类似滑动窗口,减去左边一个数,和增加右边一个数,对逆序对产生的贡献都是主席树方便维护的。
T3 距离之和
给定一棵树,一次操作支持删除一条边,再添加一条边,使图仍然保持树的形态,求对于每个点,变成树的重心,所需要的最小操作数。
一个点是树的重心的充要条件是,所有子树的大小都小于等于 \(\frac{n}{2}\) 。一棵树可能有两个重心。
考虑 \(u\) 号点,首先,我们先断掉一定数量的边,然后连边的时候,全部连到 \(u\) 上一定最优。所以我们只需考虑删边怎么删,无需考虑连边怎么连。
删边后的图,需要满足, \(u\) 所在连通块内,每个儿子的大小都小于等于 \(n/2\) ,除 \(u\) 所在的联通块外,每个连通块大小都小于等于 \(n/2\)。
对于原图(即给定的图中),记树的重心为 \(rt\) ,将无根树变成以 \(rt\) 为根的有根树后,我们删边,一定可以选择全部删与 \(rt\) 直接相连的边,因为这样得到的连通块仍然满足条件。
我们从大到小砍 \(u\) 的所有子树,直到剩下的大小小于一半,记操作数为 \(x\) 。
分类讨论:
- 记 \(u\) 的除 \(rt\) 外最高的祖先为 \(b_u\) ,如果在得到 \(x\) 的删边过程中,\((b_u,rt)\) 被删除,且连上这条边,\(u\) 仍然保持合法,则答案为 \(x-1\) 。
- 如果 $(b_u,rt) $ 未被删除,若将 \(x\) 对应方案中,砍掉的最小子树连回去,如果合法,则答案为 \(x-1\) 。
- 否则,答案为 \(x\) ,可以证明,答案不会更优(。
至此,答案只可能是 \({x,x-1}\) ,时间复杂度做到了严格线性。
T4 崇拜
给定一棵树,求 :
\[\sum _{p是一个1到n的排列} \prod dep[lca(p_i,p_{i+1})] \]$n\le500 $ 。
考虑状压,即 \(n\le20\) 怎么做。
Day3 by Smeow
T1 猫猫小游戏
给出一个 \(n*m\) 的网格,有两种颜色,初始均为无色。有两种操作:
- 选择一行染成红色
- 选择一列染成蓝色
问是否可以染成目标状态。 \(n,m\le3000\)
考虑无法染成目标状态,即形成一个类似环的结构,想到建立图论模型。
首先,重复染多次是没有意义的。一个方格 $(i,j) $ 最后颜色是 红色,说明蓝色一定在红色前被染过,则建立一条 \(j\to i\) 的边,合法的染色顺序即这张图的拓扑序,不合法只需判断是否有环即可。
T2 猫猫的数列
求满足下列条件,长度为 \(n\) 的序列 \(A\) 有多少个:
- \(a_i\le m\)
- 有且仅有一对元素数值相同。
- 存在一个位置 \(p\) ,使得 \(a_1,a_2,...a_p\) 严格单调递增,\(a_{p},a_{p+1}...a_n\) 严格单调递减。
\(n,m\le 10^{15},mod\le 10^6\) 。
完全不会类似的组合题呀,考场上写的什么 \(n^3\) 瞎 dp 还贼难调。Orz Setoff...
第一步,\(A\) 中的数字有几种?
- 由于有一个是相同的, \(\binom{m}{n-1}\) 。
- 对于剩下那一个数,要选择一个不是最大的和他相等,即 \((n-2)\) 。
第二步,这些数字怎么放?
- 先除去两个相等的,最大的那一个一定放中间,剩下的,每一个都可能放左边,可能放右边,且无论放左边还是右边,都只有唯一的位置 :\(2^{n-3}\);
答案即为三者相乘。
注意到模数很小,使用 \(Lucas\) 。
T3 多重集的错位排列
给定非排列的 \(a_i\),求有多少种改变顺序得到的 \(b_i\) ,满足 \(\forall \ b_i\ne a_i\) 。\(n\le2000\) 。
普通错排的递推式就是 \(D(n)=(n-1)\times (D(n-1)+D(n-2))\) ,就是考虑最后一步,是交换之前的一个错排,还是之前的一个非错排。
但是错排还有容斥形式,至少一个的容斥系数就是:(固定零个)-(固定一个)+ (固定两个)-(固定三个)+(固定四个)...
即:(刚好打破 \(0\) 个限制)=(至少打破 0 个限制)-(至少打破 1 个限制) + (至少打破两个限制) - (至少打破三个限制)...
写成封闭形式,即 \(D(n)=\sum (\binom{n}{i}(-1)^i\times(n-i)!)\)
回顾一下容斥原理的本质:容斥系数为正的时候,是为了求出那些最后一次有机会能求出的数。
另外,对于多重集的全排列公式,即 \(\frac{n!}{n_1!n_2!n_3!...n_k!}\) 。
考虑 \(dp\) ,设 \(f[i][j]\) 表示考虑了 \(i\) 个数字,\(j\) 个位置强制打破。数组值存的是 容斥系数×方案数。
枚举当前数字 \(i\) 强制打破了 \(k\) 个限制, $f[i][j]=\sum f[i-1][j-k]\times (-1)^k\times \binom{siz[i]}{k}\times \frac{1}{(siz[i]-k)!} $ ,和上面基本一样。
最后答案即 \(\sum f[m][i] \times (n-j)!\) 。
T4 括号
给定一个长为 \(n\) 的括号序列,支持三种操作:
- 将第 \(x\) 个位置的括号替换为左/右括号
- 查询该括号序列是否为合法括号序列。
套路题,将左括号看做 +1
,右括号看作 -1
,合法括号序列满足前缀和最小值 \(\ge 0\) 且最后一位 \(=0\) 的限制。直接线段树做即可。
Day 4 by Smeow
T1 文学游戏【FST-10】
T2 数学游戏
有 \(n\) 个数字,你可以消掉任意个质因数 \(>1\) 的数字(相同质因子只算一次),也可以使用一次数字复制器,使得 \(a_x\) 和 \(a_y\) 都变成 \(a_x\times a_y\) 。给定 \(q\) 次询问,每次询问 \([l,r]\) 的数字至少需要多少次复制器才能全部消掉。 \(n\le 10^5\) 。
显然需要将所有数字质因数分解,只有一个质因子的数是删不掉的,必须和有另一个质因子的数结合。分类讨论:【下文中,质数代指质数和只包含一个质因子的数】
- 这个区间里只有 \(1\) 和一个质因子,消不掉,输出 -1
- 对于 \(1\) ,一次只能拿 \(1\) 和合数消,若没有合数,输出 -1
- 这个区间里,出现次数最多的质数小于所有数的一半,那么每次消都可以消去两个。
- 否则,存在绝对众数,剩下的那些,一次只能消一个。
摩尔投票维护区间众数即可。
T3 地理问题
给定一张无向图,你需要给边定向,有若干条指令,要求你从 \(u\) 能走到 \(v\) ,问你何时无法满足所有指令【即指令间出现矛盾】。
图上问题很难处理,我们希望扔到树上去,考虑边双缩点,因为一个边双内,存在一个方案使得所有点两两可达的。所以我们不需要管边双内的情况。只需要管割边即可。
缩点后形成一棵树,直接树剖打 【从上到下】或者【从下到上】的标记,如果一条边同时存在两个标记,则说明非法。
T4 历史问题
给定序列 \(a_i\) , 每次询问区间 \([l,r]\) 的连续段个数有多少。一个 \([l,r]\) 是连续段,当且仅当 \(\max-min=r-l\) 。
强制在线, \(n,q\le 10^5\) 。
首先考虑离线怎么求,扫描线左端点,设 \(f_i\) 表示左端点确定,右端点为 \(i\) 时,这段区间的【数值段】个数,例如【1,2,3】【5,6】,【8】的个数为 \(3\) 。
类似 【bakery】的思路,考虑加入一个 \(a_i\) 的贡献是什么。找到 \(a_i-1\) 和 \(a_i+1\) 在前面出现的位置,排序后分别记作 \(pre_1,pre_2\) 。
那么会对 \([1,pre_1]\) 区间减一,因为两个连续段合并, \([pre_1+1,pre_2]\) 区间不变, \([pre_2+1,i-1]\) 区间减一,因为又多了一个连续段。
当然对只有 \(pre1\) 的情况要特判。
统计就是 【=1】的个数,即最小值个数,是线段树好维护的。
那么在线呢?变成一个历史和了>....< 这下成【NOIP2022】模拟赛了
Day5 by wucsdtio
T1 序列函数
定义 \(f(a_1,a_2,...,a_n)=f(a_1\oplus a_2,a_2\oplus a_3,...,a_{n-1}\oplus a_n)\) 。每次给出一个区间 \(l,r\) ,求 \(\max_{l\le i\le j\le r} f(a_i,...a_j)\) 。
\(f\) 函数直接做是非常不好做的,但是可以通过样例观察出 $f(l,r)=f(l,r-1)\oplus f(l+1,r) $,另记 \(g(i,j)=\max_{i\le l\le r\le j} f(l,r)\) ,
\(g(i,j)=\max (g(i,j-1),g(i+1,j),f(i,j) )\) 。做到 \(O(n^2+m)\) 。
T2 历史
给出一棵树,每次选择一个点和权值 \((x,val)\) 。所有和 \(x\) 距离小于等于 \(val\) 的点的 \(w_i\) 都会加上 \(max(val-dis,0)\) 。最后统一求每个点的 \(w_i\) 。 \(val\le1000\) 。
相当于一个点不断向外扩张,扩张的过程类似一个等差数列,末项为 \(0\) 。
发现 \(val\) 比较小,考虑和 \(val\) 有关的复杂度。
问题在于标记是不能“合并“的,因为如果一个权值为 \(4\) 的标记和一个权值为 \(5\) 的标记合并成一个权值为 9 的标记,就不能判断其在什么位置结束为 0 。但是同样权值的标记是可以合并的,记 \(d_{u,v}\) 表示 \(u\) 点有 \(d_{u,v}\) 个大小为 \(v\) 的标记,转移为 \(d_{u,v}\to d_{u',v-d_{u,v}}\) 。空间复杂度有点汗流浃背了:\(O(n\times val)\) 。
Sol1.换根dp
最后统一处理答案,可以直接换根做: \(f_{u,i}\) 表示以 \(u\) 为根的子树,对 \(u\) 点贡献为 \(i\) 的个数。
\(f_{u,i}=\sum f_{v,i+1}\) ;
\(g_{u,i}\) 表示 \(u\) 除子树外的部分(这样设比较好算),对 \(u\) 贡献为 \(i\) 的个数:
\(g_{u,i}=g_{fa,i+1}+\sum _{v\in son_{fa},v\ne u} f_{v,i+1}\) 。 时空复杂度均为 $O(nd) $ 。
平邑第一换根中学。
胜利第一点分中学。
T3 附魔
\(n\) 本附魔书,第 \(i\) 本附魔书初始有魔咒 \(i\) ,该魔咒对应的经验等级 \(a_i\) ,和合并过程中的累计惩罚 \(v_i\) 初始为 \(1\) 。
每次进行两本附魔书的合并,若将 \(x\) 合并到 \(y\) 上,则 会消耗 \(x\) 上所有魔咒的 \(a_i\) ,以及惩罚 \(v_y\) 的代价。同时 \(v_y=v_y\times 2\) 。
问将所有附魔都附魔到一本书上的最小代价。
显然构成了树形结构,但是需要我们找性质。
- 一个魔咒的经验等级 \(a_i\) 被计算的次数,等价于其在原树的深度。因此应该将 \(a_i\) 大的填上面, \(a_i\) 小的填下面。
- 一个点获得的惩罚,与其儿子的数量 \(x\) 有关: \(\sum_i^{x} 2^i=2^x-1\) 。因此,一个点不应该有过多儿子,将儿子挂到该层上另一个儿子少的点上,一定不劣。
综上,我们可以规范化地得出结论(这里定义度数是儿子数量。
- 同一层上每个点的度数最多差 \(1\) 。
- 父节点的度数一定大于等于子节点度数,否则把子节点挂到上一层不会劣。
也就是说,我们按照 bfs 的过程得到的每个点的度数,一定是一个不增的序列。然后就可以 DP 了,设 \(dp[i][a][b]\) 表示当前层的第一个节点为 \(i\) ,这一层有 \(a\) 个节点,下一层有 \(b\) 个节点,需要枚举每一层的度数。
T4 曼哈顿
给定一张网格图,你需要遍历每个点并回到起点,每一次移动的价值是两点间的曼哈顿距离。问价值最大是多少?
转换:等价于每一条网格线被跨过的次数之和。
思路:构造理论最大值。
对于一条线,其左边有 \(a\) 个点,右边有 \(b\) 个点,被跨过的理论最大值就是 \(2min(a,b)\) 。
然后,如果最中间的线达到了理论最大值,则其他平行与他的线也达到了理论最大值。
于是只需考虑最中间的横线和竖线。
那么考虑一张 \(2*2\) (偶数×偶数)的图,手摸发现构造不满,是理论最大值-2。
再考虑有奇数的情况,最中间的线有两条,也是一样道理。
Day 6 by wucsdtio
T1 铺设积木 roadblock(2013,2018,2023)
差分练习题,+没用的oi冷知识
T2 开关灯
\(n\) 盏灯,初始全为 熄灭,对于第 \(i\) 次操作,选择 \(i\) 的所有质数倍标号的灯,并把他们状态翻转。
求 \(n\) 次操作后,有多少灯是开的。 \(n\le5\times 10^7 ,10^{10}\)
不妨分块打表
一开始可能不是很好线性筛,但是如果将开灯设为 \(f=-1\) ,关灯设为 \(f=1\) ,那么对于 $x=p_1{q_1}...p_m $ , \(f(x)=(-1)^m\) 。很好的形式。满足非完全积性函数的性质,\(f(xy)=(-1)^{m1+m2},\gcd(x,y)=1\)。可以进行线性筛。剩下的留给亚线性筛。
T3 历史 Plus2.0
给出一棵树,每次选择一个点和权值 \((x,val)\) 。所有和 \(x\) 距离小于等于 \(val\) 的点的 \(w_i\) 都会加上 \(val\) 减去距离的值。单点询问 \(w_u\) 的值,\(val\le 10^9\) 。
和上一题不同的是,不再受 \(0\) 的限制,但值域也升到了 \(1e9\) ,并且需要支持过程中查询。
一眼根号重构吗这不是。散块直接找距离,可以用线性 lca。重构直接借助昨天的思路——换根dp。
设 \(cnt_u\) 表示 \(u\) 子树内这样的点的个数, \(f_{u}\) 表示 \(u\) 子树内,所有点对 \(u\) 的影响。 \(g_u\) 表示 整棵树对 \(u\) 的影响。
\(cnt_u=\sum cnt_v+[u],f_u=\sum (f_v+cnt_v)+val_u\) 。
\(g_u=g_{fa}+cnt_u-(cnt_1-cnt_u)\) 。
这样 \(O(n)\) 就可以根号重构了,复杂度不多带 \(\log\) 。跑的飞快。
对于 \(polylog\) 的做法,考虑这东西就是一个树上加等差数列。
T4
Day7 by chunzhen
T1 树的直径,T2 slyz模拟赛T4 \kt\kt。
T3 Yazid 的新生舞会
给定序列 \(a_i\) ,求有多少区间 \([l,r]\) 满足存在区间绝对众数。
Sol1.根号分治
问题首先转换为枚举每个值 \(x\) ,将所有等于他的设成 \(1\) ,否则设成 \(-1\) ,这样一个区间有绝对众数,等价于存在一个区间的和大于等于 \(0\) 。复杂度 \(O(n^2\log)\) 。
第二步的操作就很想根号分治,对于一个数出现次数大于 \(B\) 的,则这样的数不会超过 \(n/B\) 个。可以直接暴力。否则,对于每一个这样的数,其可能会作为一个区间众数的区间长度都不会超过 \(2B\) 。我们可以最后统一扫一遍,复杂度 \(O(n^2\log/B+n\times2B)\) ,\(B=\sqrt{n\log}/2\) 左右比较好。复杂度 \(O(n\sqrt{n\log n})\) 。
Sol2.三阶差分树状数组 线段树
一个区间的和大于等于0,本质就是求前缀和数组的顺序对。注意观察前缀和数组,因为有大量 \(-1\) 的存在,所以相邻两个 \(x\) 之间的一堆 \(-1\) 在 \(s\) 数组上的体现就是公差为 \(-1\) 的等差数列,即一段 \([s,e]\) 。开一个桶 \(c\) 记录。再开一个桶 \(d\) 记录 桶 \(c\) 的前缀和。
Sol3.分治
很容易想到分治结构,一个数能够作为当前区间的绝对众数,要求出现大于一半,那么他一定是左儿子的绝对众数或右儿子的绝对众数。
T4 仓皇逃跑 √
给定一棵树,以及多条路径,边有 \(k\) 种颜色,每条路径要求这条路径上至少有两种颜色,问满足条件的树有多少种可能。\(n\le60,m\le15,k\le10^9\)。
考场上爆写 subtask 怒切 60分。
考虑只有两条路径且相交的情况怎么做,需要分类讨论:相交部分有一种颜色还是两种颜色。
很麻烦,但是可以将问题容斥一下,转换成一条路径上只有一种颜色。这很方便用并查集维护。并且数据范围小,可以直接容斥。
也就是枚举不合法边组成的集合 \(S\) ,对于每个集合的容斥系数为 \((-1)^{popcount(S)}\) ,对于相交的路径压成一条,枚举即可。
Day8 by WHQ
T1 分数约分
爆搜。但写挂了
T2 共享单车
学校看做一张无向图,有 \(k\) 个点上有共享单车,汽车速度是 \(y\) ,步行速度是 \(x\) ,但是第 \(i\) 辆单车有 \(p_i\) 的概率开锁失败,问从起点到终点,采取最优策略的最小期望时间是多少? \(n\le10^5,k\le 18\)
考虑一档 \(n,k\) 同阶,非DAG的图上 dp 是非多项式的,直接考虑状压,表示走过了哪些点。倒序枚举,然后就可以 \(dp\) 无后效性地转移了。
如果 \(n\) 更大,发现处理其他的点都是没有意义的,我们只关心有单车的 \(k\) 个点,预处理 \(k\) 个点间两两最短路即可。
T3 积木拼接
给定 \(n\) 个字符串 \(s_i\) ,选出一个子序列,满足是回文串的方案有多少? \(n\le 100,\sum |s|\le 10^5\)。
不会
T4 [六省联考 2017]
维护一个数据结构,支持:
- 给定 \(x,l,r\) ,将区间 \([l,r]\) 的 \(a_i\to x^{a_i}\) 。
- 给定 \(l,r\) ,输出 \(\sum a_i\bmod p\) 。
\(n,m\le 5\times 10^4\)。
本题暴力就比较难做,修改是不带取模的,查询是要带取模的。
首先需要拓展欧拉定理:
\(a^x=a^{x\bmod \phi(p)} \mod p\) , \(a^x=a^{(x\bmod \phi(p))+\phi(p)}\mod p\) 。(不互质)
因此我们需要维护的是,一个类似幂塔的结构,即 \(x_1^{x_2^{x_3^{a_i}\bmod \phi(\phi(p))}\bmod \phi(p)}\bmod p\)
另外, \(p\to \phi(p)\to \phi(\phi(p))\) 是呈指数下降的,因为对于一个奇数会变成偶数,一个偶数至少会减半。所以至多 \(O(\log )\) 次模数变为 \(1\) ,上面的部分就不用管了。
因此线段树上一个位置维护一个队列,时刻保持队列的长度是 \(\log\) 以内即可。
复杂度多一个 \(\log\) 在矩阵乘法上,预处理光速幂即可。
Day9 by lxl
T1 查询
给定三个序列 $a,b,c $。求 \(a_j+b_j\times c_i\) 的第 \(k\) 小值。
前 \(k\) 小单调队列,第 \(k\) 小二分答案。二分答案后检查小于 \(x\) 的个数,枚举一维 \(j\) ,显然 \(i\) 有单调性。
T2 枚举
给定 \(x,y\) ,求三元组 \((a,b,c\le n)\) 的个数满足 \(((x^2+1)\bmod a+b)\bmod c=y\) 。同时需要输出字典序前 \(10^5\) 小的三元组。
先考虑一个 \(O(n^2)\) 做法,枚举作为模数的 \(a,c\) 。此时 \(b\) 是一个区间,然后我们可以直接加到 \(vector\) 里直到超过 \(10^5\) ,最后再排序。
尝试把取模展开,记 \(z=(x^2+1)\bmod a+b\) ,\(\lfloor\frac{z}{c}\rfloor\times c+z=y\) 。枚举 \(c\) 和 \(\frac{z}{c}\) ,这样是调和级数的。
这样得到合法的 \(a,b\) 的个数也是 \(O(n\lg n)\) 的。
T3 决斗 √
\(A\) 和 \(B\) 决斗扑克牌,\(A\) 先手,已知 \(A,B\) 的出牌序列,\(B\) 事先知道 \(A\) 的出牌顺序。规则是点数大的获胜。 \(B\) 只希望他获胜的局数尽可能多。而且出牌的字典序要尽可能大。输出出牌顺序。
最多的获胜局数是比较简单的,采用田忌赛马的战略,每次 \(B\) 出大于 \(A\) 的最小的,如果没有就出自己最小的。这样我们可以得到第一问的答案。
但这种策略和第二问是矛盾的,字典序问题逐步确定答案,不难发现每一步能出的牌是一个区间,我们要填这个区间的最大值。且不会影响答案。
使用线段树的信息合并解决带修改问题,将原问题扔到数轴上, \(A\) 的数字记作 \(a_i\) ,\(B\) 的数字记作 \(b_i\) 。一个序列上区间的最多获胜局数 \(ans\),本质就是每一个 \(a_i\) 和 \(b_i\) 的匹配,记 \(ans\) 为答案, \(cnta\) 为剩下了多少个 \(a_i\) ,\(cntb\) 为剩下了多少个 \(b_i\) 。\(ans[p]=ans[ls]+ans[rs]+min(cnta[ls],cntb[rs])\) ,\(cnta[p]=\sum[a_i] -ans[p]\) 。 \(\sum[a_i]\) 为原序列上 \(a\) 的总个数。
又因为 最大值是有单调性的,所以可以枚举一个 \(i\) 代表当前填第 \(i\) 个位置,二分一个 \(mid\) ,线段树上进行 \(i\) 这个位置上删除一个 \(a_i\) ,\(mid\) 上删除一个 \(b_i\),检查根节点的答案是否只减少 \(1\) 。
优化到单 \(\log\) 可以线段树上二分。
T4 Bamboo#2
Tag:时光倒流
\(n\) 棵柱子,初始高度为 \(h_i\) ,每天都会长高 \(a_i\) ,每天长高前,你有 \(k\) 次机会去砍竹子(可以砍同一棵),每次砍的高度都是 \(p\),但是竹子不能被砍成 \(0\) ,问 \(m\) 天后最高柱子最矮是多少。
时光倒流的好题,首先二分答案 \(mid\) ,因为有 \(0\) 的限制,问题转换成初始竹子高度都是 \(mid\) ,每天可以拔高 \(k\) 棵竹子,竹子自己会变矮 \(a_i\) ,问能否使得最后所有竹子高度都大于等于 \(0\) 。
此时,竹子拔高不再受 限制,也没有 \(h_i\) 的限制。直接贪心做是对的,用堆维护每个竹子到 \(0\) 的时间即可。
Day9+1 by lxl
T1 树
树上黑白染色,先手染黑色。如果最后存在一个黑点周围没有任何一个白点,则黑点胜,问先手是否有必胜策略。
又是被 T1 创死的一天,先观察链怎么做...只要链长度是奇数,先手都能胜利,首先三个节点的情况是先手必胜的,然后对于其他的奇数,都可以通过选择左数第二个点,而转换成先手必胜的子问题。
菊花要更简单一些,只要大于一个点,那么选择中心节点,下一步就能赢。
再分析一下策略:先手尽可能选择叶子的父亲,诱惑后手选择至少一个叶子,如果有多个叶子就赢了。
对于有一个叶子的情况,可以认为是:同时删去这两个节点,如果一个点被删两次,则先手赢 。
T2 异或 popcount
\(q\) 组询问,给定区间 \([l,r]\) ,对于每个 \(k\in[0,31]\) 求多少组整数对 \((x,y)\in[l,r]\) ,满足 \(x \oplus y\) 有 \(k\) 个二进制为 \(1\) 。
数位 DP
T4 萌萌哒在线询问版
给定一个字符串,每次两种操作:
- \([l,r]\) 是一个回文串
- 询问 \([l1,r1]\) ,\([l2,r2]\) 是否相等。
首先可以转换为:正反各建一个哈希表,这样就转换成了 萌萌哒的在线询问。
本来萌萌哒是离线 ST 表,为了支持在线,我们使用线段树维护哈希。
暴力做问题在于合并的次数太多,而有些点是合并过多次而没有必要的。
对于修改两个区间相等的操作,我们不断二分,找到第一个满足子段哈希不相等的位置,然后将两个不相等的位置合并,并将两个子段的哈希修改成相等。
这样总合并次数是 \(O(n)\) 的,每次二分查找+线段树是 \(O(log^2)\) 的,因为我们需要记录并查集内具体是哪些点,所以启发式合并。
void merge(int u,int v) {
u=find(u); v=find(v);
if(u==v)
return;
if(vec[u].size()<vec[v].size())
swap(u,v);
for(auto x:vec[v]) {
update(1,x,u);
vec[u].push_back(x);
}
fa[v]=u;
vec[v].clear();
}
int get_diff(int l1,int r1,int l2,int r2) {
int l=1,r=r1-l1+1,ans=-1;
while(l<=r) {
int mid=(l+r)>>1;
if(query(1,l1,l1+mid-1)!=query(1,l2,l2+mid-1))
ans=mid,r=mid-1;
else
l=mid+1;
}
return ans;
} q
while(m--) {
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
while(true) {
int val=get_diff(l1,r1,l2,r2);
if(val==-1)
break;
merge(l1+val-1,l2+val-1);
l1+=val; l2+=val;
}
}