2024.11 做题笔记

2024.11 做题笔记

其实是 CSP 后到 NOIP 前的部分,主要记录模拟赛题

10.28

怎么 KTSC 这么困难啊……

B. P11237 「KTSC 2024 R1」警察与小偷

把警察、小偷所在路径拎出来,此时警察一定往小偷所在方向走,而小偷可以在警察到路径上的某点之前从这点走向路径外,想选尽量长的路径,让警察走的尽量多

但可能警察在小偷走到路径末尾之前就抓住他了,所以其实要求的是类似 maxx{min(追上时间,警察走到底部时间)}

小偷拐弯的点 x 离警察越近,警察追及的距离越短,追上时间越短,而小偷多走一点,能走到的子树变多,路径更长,警察走到底部的时间更长

所以 min 内在离小偷出发点越远时前者递减,后者递增,于是可以二分/倍增找出分界点,分界点前后就是小偷所拐弯的位置

计算时间可以用倍增,就能处理出点 x 的父节点在挖掉 x 所在子树后往子树内能走到的最远距离和包括子树外后能走到的最远距离,追上时间能直接根据所在节点算出追及距离,时间复杂度 O(nlogn)

我赛时没想特别清楚,从警察所在路径端向上倍增时我以为判断时要算 lca 到这个点这段的点往外走的最远距离,还要用一个倍增,复杂度就变成了 O(nlog2n),实际上可以直接取 x 在去掉那个子树后能走到的最远点

C. P11236 「KTSC 2024 R1」水果游戏

考虑对固定的序列如何求最大值,把相同的水果缩成一段,种类为 x,有 c 个,发现如果有三段 (x1,c1),(x2,c2),(x3,c3) 满足 x2<x1,x2<x3,则把 x2 全部合并成 min(x1,x3) 后,x1,x3 才可能发生合并,否则相当于从 x2​ 处断开序列

所以连续序列不存在 x2<x1,x2<x3 的情况,则它是单峰序列,单峰序列的最大值好求,直接把两边全部尽可能往上合并即可

用栈模拟这个过程,加入一个数时如果发现末尾的三个数满足上述条件就尝试合并

  • x2 不能合并完全,则往栈内插入 (x2,c2),再插入 (,0) 作为分隔符,再插入 (x2,c2),(x3,c3)
  • 否则直接把 x2 全部合并成 min(x1,x3)​ 再插入栈中

由于值域很小,因此单峰序列长度很短,直接上线段树,维护每个节点合并后的结果

注意这里的插入是递归插入,而且分隔符可以自动帮我们把很多段单峰序列收折起来,插入 时如果序列末端在单调递减就相当于合并了单峰序列的后侧,如果把单峰序列插入一个 后面则是合并它的前侧,最后只会留下一整段单峰序列或中间是分隔符,两端为单增、单减序列

所以线段树上不用分开维护前后缀,每次直接暴力把后面节点的序列中的元素依次插入到前面即可

复杂度 O(nVlogn)

合并的代码:

void add(info &x, pii w) {
	if(w.se)	x.mx = max(x.mx, w.fi + __lg(w.se));
	if(x.seg.empty())	return x.seg.pb(w), void();
	if(x.seg.back().fi == w.fi)	return x.seg.back().se += w.se, x.mx = max(x.mx, w.se ? w.fi + __lg(x.seg.back().se) : 0), void();
	if(x.seg.size() <= 1)	return x.seg.pb(w);
	pii u = x.seg[x.seg.size() - 2], v = x.seg.back();
	if(v.fi < u.fi && v.fi < w.fi) {
		pii nw = min(u, w);
		if(nw.fi < inf && v.se % (1 << (nw.fi - v.fi)) == 0) {
			x.seg.pop_back();
			add(x, {nw.fi, v.se >> (nw.fi - v.fi)}), add(x, w);
			return;
		}
		x.seg.pop_back(), x.seg.pop_back();
		add(x, {u.fi, u.se + (v.se >> min(u.fi - v.fi, 30))}), add(x, {inf, 0}), add(x, {w.fi, w.se + (v.se >> min(w.fi - v.fi, 30))});
		return;
	}
	x.seg.pb(w);
}
info operator + (const info &x, const info &y) {
	info nw(x);		nw.mx = max(nw.mx, y.mx);
	for(auto i : y.seg)	add(nw, i);
	return nw;
}

10.29

A. #4260. 「KTSC 2024 R2」岛屿

遇到多边形就头大,怎么办?

图本身不满足要求,下界是加一个点

有个初级的想法是将多边形最外面一周缺一条边当第一棵生成树,中间的边加上那条边,经过一些调整发现在一个度数为 2​ 的节点处还需要加一个点,但是如果真的这样调整将会非常麻烦

考虑直接构造,如果有形如 (x,z),(y,z) 的边且当前 x,yT1,T2 中均连通,则直接把两条边分配给两棵树即可

找到一个度数为 2 的点,它和相邻两个点一定组成小三角形,在它们中间加一个点,设它们分别为 (x,y,z),w,则 T1 中连 (x,y),(y,z),(y,w)T2 中连 (x,w),(z,w),(y,z)

此时这个小三角形就能去掉了,且 y,z 此时连通,再依次去掉三角形即可,三角形两条边分别分配给两棵生成树

B. P11239 「KTSC 2024 R2」跳跃游戏

我记得国赛前好像做过一个类似这样的用线段树维护 DP 值,但我怎么还是调试到红温啊?

题意可以转化为选若干个间距 k 的黑色点,每个黑色点产生 ai 的贡献,要使总贡献最大

最朴素的 DP 是设 fi 表示考虑了前 i 个点时的贡献,fimax(fi1,fik+ai)

n 很大,但段数很少,考虑优化,发现每次特殊的转移都是从前 k 个转移,用线段树维护 1k 个的 DP 值,维护区间最大值,每次一整段转移,维护当前的开头 st,转移的一段 sted 就是区间加

与前一个取 max 的操作,相当于取前面的最大值而不进行区间加,由于 DP 的性质,f 数组不降,因此 st1 的位置就是转移前最大值,线段树上二分出哪个数之前是取 max​ 更优,剩下的区间加

细节比较多,尤其是一段比较长,转了一整圈时,把两端的散段单独拿出来,中间的整段单独转移一次,剩余次数就直接做区间加

C. P11241 「KTSC 2024 R2」病毒

每个点都能传播邻域,暴力就是直接跑 dij,每个点拆成出点和入点,入点向出点连边权为 ci 的边,每个人也是一个点,向自己邻域的入点连边,邻域的出点也向它连边

考虑优化建图,建出点分树,点分树每个点处用前缀/后缀和优化建图

点数和边数都是 O(nlogn) 的,复杂度 O(nlog2n),但边权不为 0 的点只有 O(nlogn) 个,可以在 dij 的过程中直接转移这些边连接的点,把它们单独放到一个队列中,每次队列中有点就取出

11.1

B.

考虑刻画操作,用线段树或 Trie 维护区间和,位置对 xand 操作看成将 x0 的位代表的层右节点合并到左节点,同理取 or 则是把是 1 的位那层左节点合并到右节点,xor 则是经典的交换左右子树

这些都可以打上标记,每次下传,注意标记之间的顺序,规定先合并后交换,当前只有最后一次合并操作有用,且合并操作前的交换操作无效,合并的复杂度同线段树合并是均摊的,每次单点加只会增加 O(logn) 个节点,总复杂度 O(nlogn)

C. 朋友

每条鱼能到的是一个区间,且这些区间只会在端点处相交

而且显然把鱼更集中更好,关键的位置只有 O(m) 个,区间 DP,设 f(l,r) 为只考虑被 l,r 完全包含的区间时 [l,r] 的答案,枚举当前区间想把鱼集中到的鱼缸为 k,则被 [l,r] 完全包含的区间如果包含 k 就放在 k 处,f(l,r)maxkf(l,k1)+f(k+1,r)+(ck2)

复杂度 O(m)

赛时没有考虑区间在端点相交的情况,把区间按包含关系建树,考虑每个子树,每次会从叶子选到根,又分为若干个子树,实际上做的就是这个区间 DP,但为什么我一定要建树啊?

D. QOJ5089 环覆盖

一张图能环覆盖的充要条件为每个点的度数是偶数

必要性显然,充分性是图有欧拉回路,回路上如果重复经过一个点就把那个环提出来

朴素的状压 DP 为 fj,i,s 为考虑了前 j 条边,选了 i 条边,度数为奇数的点集合为 s 时的方案数,复杂度为 O(2nm2)

用集合幂级数刻画,设 G=(1+yx{u,v}) 要求的是 [x]G,其中对 x 做异或卷积,对 y 做乘法卷积,答案是一个关于 y 的多项式的各项系数

集合作为指数可以看作集合对应的 2n 个二进制数作为上标

然后使用 FWT 优化,观察 [xS]FWT(1+yx{u,v}),由于 [xS]FWT(F)=T(1)|ST|[xT]F,则 S 与集合 {u,v} 的交只有没有元素,有一个元素,有两个元素这三种可能,因此 [xS]FWT(1+yx{u,v})=1+y/1y[xS]FWT(G) 一定形如 (1y)k(1+y)mk

所以可以枚举 S,算出 [xS]FWT(1+yx{u,v}),能 O(2nm) 得到 FWT(G),然后 IFWT 回去得到 [x]G

但我们只需要 [x]G,且 [xS]F=12nT(1)|ST|[xT]FWT(F)

这是根据 FWT 的过程,FWT 是 merge(a0+a1,a0a1),IFWT 为 merge(a0+a12,a0a12)

所以我们只需要算 12nS[xS]FWT(G)

对每个 k 预处理多少个 S[xS]FWT(G) 对应 (1y)k(1+y)mk,即可在 O(m2) 时间内计算

预处理可以直接以合适的方式枚举 S,则 k 就是只有一个端点在 S 中的边数,用 bitset 维护所有边端点在 S 中个数的奇偶性,每次加入一个点就将 bitset 异或它邻边对应的 bitset,这里用 dfs 的方式枚举即可,复杂度 O(2nmw),交一发就到了 QOJ 最快解最后一面

好像预处理部分魔改高位前缀和可以做到严格 O(2n+m2)

11.2

C. 放假

赛时想了半天才勉强对无限字符串有一些感觉,但我怎么会认为 AC 自动机上有本质相同的环啊?

考虑走出环的本质是走一圈形成串的后缀能匹配完起始节点串的前缀,从同一个位置开始匹配,如果有两个位置不同但本质相同的环,则说明同样的无限长循环的串在自动机上匹配了两个位置,这是有问题的

建出 AC 自动机,求出不能到达的节点,将剩下节点间连边形成的图拿出来

串由于双向无限,所以可以从 AC 自动机任意节点出发,不一定是根

将图中的强连通分量缩点,建出新的 DAG,如果有两个环有公共点,则可以在第一个环上走,再在第二个环上走任意圈,最后回到第一个环,形成任意多个串,所以一个强连通分量只能是单点或环

同理如果有 >2​ 个在同一条路径上的环,则也有任意多个

合法串是一个环或一个环接一段路径再接一个环

在 DAG 上 DP,求出以环开头并以环结尾路径数

D. 普及组题

写起来跟答辩一样的树哈希题……

放一个我写在 NFLSOJ 上然而不说人话的题解:

题目大意是给一棵 n 个点的树,把原树复制了一棵后在这两棵树里面各删去一个编号不同的点,打乱点的编号后给出这两个删点后的森林,你需要给出一种原树的构造或判定无解,n1000

我们考虑将删点前的两棵树调整至相同的根,再判断森林是否能把点加上后使两棵树同构,设这两个森林为 T1,T2

删去的点编号不同意味着 T1 中被删的点一定能在 T2 留下来的点中找到对应点,反之同理。

T1,T2 中连通块的个数分别为 c1,c2,点 xTi 中的度数为 degi,xT1,T2 中删除的点为 a1,a2

T1 中被删除的点为根,这样的好处是它的子树全部都确定了,在 T2 中枚举它的对应点,假设为 x,则 deg2,x=c1/c11c11 的情况是 x 连接了在 T2 中被删除的点,只有一些细节上不同。

此时 x 所在树以 x 为根,去掉 x 后得到 t1,t2,tk(k=deg2,x)棵子树,其中一定能找到 c11 个分别与 T1c11 个连通块对应(同构),而 T1 中不能找到同构的树 S 则一定是 T2 中删除了一个点造成。

如何判断两棵树能否对应(同构)是经典的无根树同构问题,找出树的重心,以它为根做树哈希,判断哈希值是否相同,如果树有两个重心则各做一次,取较大的哈希值。如何树哈希可以参考 这篇文章

  • k=c11,则 T2 中非 x 所在连通块由 a2 连接后形成的树与 S 同构。

  • k=c1,设 ti 没找到同构,则 tiT2 中非 x 所在连通块由 a2 连接后形成的树与 S 同构。

判断几棵树用一个点连接后是否能与 S 同构,还是采用类似的方法,枚举 S 中与 a2 对应的点,让 S 以对应点为根,看去掉对应点后形成的子树是否都能与那几棵树对应,即将这些树的哈希值排序后看两个哈希值组成的集合是否相同。注意这里再次枚举对应点并判断一次复杂度是 O(deg) 的,所以均摊复杂度是正确的。

如果两次找给定点均找到了符合要求的,则有解,否则无解。构造方案在理解了前面判定的基础上是简单的,我们可以直接以 x 为根的树为雏形,若 k=c1 则断开它与 ti 的连边,再枚举 S 中哪个点与 x 有连边,找到正确的点后将 S 拼上去即可。

代码实现上细节很多,需要对每个点预处理它所在树中去掉它后形成的子树的哈希值以及 T1,T2 中每棵树的哈希值。

时间复杂度 O(n2logn),如果把将子树的哈希值排序这部分预处理精细实现可能可以做到 O(n2)

赛时代码,可能比较丑(

我只有看了 T3 发现一点不会后才会去开这种题。

11.4

哎一早上莫名其妙开始胃疼,然后比赛挂大分!

nlog2n 2s 过不了 2×105,少判一个条件过大样例 WA 成 6pts……

C. P10101 [ROIR 2023 Day 2] 一个普通的字符串问题

把相邻字符 xy 看成图上有 xy 的一条有向边,则要数图中的欧拉路径数

使用 BEST 定理,枚举起点终点,连终点到起点的边,钦定这条边在欧拉回路末尾

如果图有欧拉回路,求出此时图的欧拉回路数量,则就是要求的欧拉路径数

还有一个问题是这里起点终点都相同的边不做区分,和 BEST 定理求的有差别,那就再除以 num(u,v)!

11.5

B. 集合划分

划分的要求比较严格,从最大的元素分给谁开始考虑,设当前全集为 S

  • SA,则 B 中所有元素的或不是 S,意味着 B 中所有集合都没有某一位 iS,反过来说明所有包含 i 的集合都在 A 中。现在只考虑不含 i 的集合,发现它放到 A 中后和所有包含 i 的集合并得到的集合一定都 A,只用考虑不包含 i 的集合满足限制就行了。发现问题就变成了 S/{i} 的子问题,可以递归进行

  • SB,同理分析,不过注意含有 i 的集合不能有 A​ 必须选的

f(S,x) 表示当前全集是 SA 能否选 x 个,第一种转移是 f(S,x)f(S/{i},x2|S|1),第二种是 f(S,x)f(S/{i},x)x 要么比 2|S|1 大要么不大于它,两种转移只可能有一个成立

初始从 f(2n1,k) 开始记忆化搜索,因此发现 Sx 一一对应,状态数只有 O(2n)(实际上 x 一定是 kmod2|S|),判断能否转移则用高维前缀和预处理,复杂度 O(n2n)

C. QOJ5173 染色

咋简单贪心都不会了???

假设走一步就要染色一次,需要 2(rl) 次染色,但如果一个段两端颜色相同,就可以通过把这一段染成两端颜色使得能少染一次色

这些段要求首尾颜色相同且只能在端点处重叠

考虑单组询问的做法,使用贪心,从右往左,贪心选左端点更靠右的区间

固定当前端点后后面选的区间是固定的,那多组询问就用倍增优化跳的过程即可,复杂度 O((q+n)logn)

n 比较大,每组询问都倍增常数很大,过不了,可以把询问离线,所有右端点一起跳,也可以把树建出来,扫描询问区间左端点,使用并查集维护,复杂度 O(nα(n))

D. QOJ7855 不跳棋

这题但凡放 T3 我就开了……

考虑离线问题的做法,可以倒着加入点,用点分树维护,点分树上 x 维护点分树上 x 子树内点到它的距离,每次更新最小值,不用将同一子树内的去重,因为重复的肯定不能贡献到最终答案

那在线问题只能删点,用桶维护每个距离的点数,再维护两个指针,表示 x 子树内与 x 前二小的距离,每次删除则暴力移动指针,还要维护答案的桶,记录距离为 d 的点对的数量,答案指针在每次删除完后也要移动,复杂度 O(nlogn)

记录一个部分分中用到的结论:在距离最近点对距离为 d 时,点集大小 2(n1)d

11.8

C. 山遥路远

考虑合法括号串的构造过程,可以同时在整个串两端加一对左右括号,或者把两个合法的串拼接

dis(x,y) 表示 xy 且形成合法括号串的最短路

第一种转移如果直接枚举两端到的点是 O(m2) 的,所以要记录辅助状态 dis(1,x,y),dis(2,x,y) 表示左/右多一个括号时的最短路,分步转移

第二种转移则类似 Floyd,枚举另一个点 i,可以更新 xyiixy

这里边数是 O(nm+n3) 的,点数是 O(n2),用 priority_queue 朴素维护是 O((n3+nm)logn) 的,数据比较水好像可以过,但后来被 hack 了,使用 pb_ds 中的高级堆可以做到 O(n3+nm)

有一种比较简单的维护方法:发现取最小值只有 O(n2) 次,但修改有 O(n3) 次,时间复杂度不平衡,用根号平衡的思想,每 n 个一块,修改只有取 min,可以做到 O(1),查询则暴力找出最小值,然后再暴力更新最小值所在块新的最小值,复杂度 O(n3+nm)

D. 命运歧途

O(n2) DP 都不会了???

把差为 k 的数连边,形成了 k 条链,每条链的长度为 nknk+1

考虑容斥,求出钦定了 i 个相邻位置不满足要求的方案数 fi,相当于选了 i 条边,会分出 ni 条链,这些链有 (ni)! 种放法,但不是单点的链还有正反两种放法,所以 DP 时需要记录最后的链是否为单点,DP 出 1n 每种链长,复杂度 O(n2)

答案为 i=0n(1)ifi

每次询问 k 时要做背包合并 DP 数组求出 f,要做 k 次合并,背包大小为 n,每个物品的大小为 nknk+1,朴素合并复杂度为 O(n×(k×n×nk))=O(n3)

发现物品的大小变化只有 O(n) 次,且在所有大小下数量的变化量总共也是 O(n) 的,每次可以撤销背包,撤销加入的复杂度为 O(nkn×nk)=O(n2logn),重构的复杂度为 O(n2n),常数比较小,于是就可以通过了

但是为什么换一种定义 DP,记录剩下的链数,撤销时就要支持 /2 不好做了啊?是模数可能是偶数还是太超前了吗?

11.9

B. P10260 [COCI 2023/2024 #5] Rolete

最优情况一定可以看作先整体上升,然后手动调整个别不满足要求的,离线询问,从大到小扫描 h

窗帘自动升起 x 厘米需要的时间 fx 是分段函数,可以预处理出所有 fx

对于固定的 h,想找出最优的 x

感性理解,在 h 固定时整体上升 x 厘米总共花费的时间 tx 关于 x 是下凸函数

于是每次可以三分 x 的取值,复杂度 O(nlognlogV)

再次感性理解 h 越小,窗帘需要上升的高度越高,自动升起所有的窗帘的次数不降,于是有决策单调性,用指针维护 x 的取值,复杂度 O(nlogn),瓶颈在每次计算 tx 时二分找到哪些窗帘高度 >h+x,用桶维护可以做到 O(n)

C. 直径

各显神通构造题,默认 1 为根同时也是直径中点

我赛时的方法为设 1 的各棵子树叶子数量分别为 a1,a2,,ami=1mai=t,让每个叶子都可以成为直径端点,则直径数量 ×2t2i=1mai2

枚举 t,则 i=1mai2=t22k,先假设 ai 全部为 1,此时还差 t2t2k,考虑合并 i1 会增加 i(i1) 的贡献,要合并的 1 的个数 t,合并越多单位贡献越多,因此 i 从大往小贪心,能合并就合并,我不觉得这样最优,但应该不会很劣,打表验证可过

实际上 m=2/3 即可覆盖所有情况,枚举两棵子树的大小可以算出第三个

时间复杂度都是 O(n2)

但这个题到底想表达什么?为什么现有的做法都是「暴力验证数据范围内可以通过」?

D. QOJ8951 澡堂

这细节也太困难了……

先考虑 m=1 的做法,找出快速刻画等待时间的式子,发现一个人 i 的等待时间为 maxj<i(tj+(ij)T)ti,因为他只会被前面最慢的人给卡住

si=tiiT,则等待时间为 maxj<isjsi,考虑 sj 对后面第一个比它大的 s 之前的数都有贡献

因此每个数跳到的下一个位置是固定的,贡献可以通过倍增计算

考虑 m>1 时,如果没有修改,则每个人使用的位置是固定的,可以看作是 m 个序列做上述 m=1 的问题

如果产生修改,则是把一个数从序列中拿出来再插入另一个位置,它会影响后面一段的贡献,因为修改后它可能成为新的最大值

设修改前的位置为 x,修改后会放在位置 y 的前面,先令 x<y1,则 [0,x1] 正常计算,[x+1,y1] 先倍增跳过前面 [0,x1] 的前缀最大值管辖的部分,后面正常计算,对于 [y,n1] 的部分同理,做一些细节处理的 dirty work

但注意去掉一个数后,中间的部分所在的序列会更改,而且在各自序列中的下标也可能会变,si 的值会 ±T,倍增时细节特别多

复杂度 O((n+q)logn)

11.11

B. 东百演说家

哎怎么出数论啊?咋特判 w=2 还能挂啊?

下面默认所有的月份,日期和星期都是从 0 开始计数,月份为 0m1,日期为 0d1,星期为 0w1

那么列出符合要求的式子:

dx+ya(modw)dy+xb(modw)0x,ymin(m1,d1)=lim

yadx(modw) 代入下面的式子,得到 (d21)xadb(modw)

先解决如何计算 xa(modw)x

由于 0lim0w1 循环了limw 次,因此取模后为 0w1 的每种取值至少有 limw 种,特判最后一段不完整的循环,如果 limmodwx 则还要加上 1

进行分类讨论

  • d0(modw) 时,直接算 xb,ya(modw)(x,y)

  • d21(modw) 时,可以解出 x(adb)(d21)1(modw),然后回代把 y 解出,转化为 xb,ya(modw) 的形式

  • d21(modw) 时,意味着两个方程实际上只有一个。将 d21 因式分解为 (d+1)(d1)

    • 注意到在 w2d+1,d1 不能同时为 w 倍数,可以用两式相加或相减得到 (d+1)(x+y)a+b(modw)(d1)(xy)ab(modw),选一个就能解出 x+yxy

      这也可以用二次剩余直接推出,由于 w 为质数,因此 d21(modw)d±1(modw)

      xmodw 的值确定时 ymodw 的值也确定了,w(xmodw,ymodw) 中贡献只有三种情况,是根据 x,ymodw 的值确定时个数是 limw 还是 limw+1 决定对总答案的贡献。不能枚举 xmodw 的取值,反过来算出每种贡献的个数,求出 x,y 都在 limmodw 内的对数 numx,y 有一个在 limmodw 内的对数就是 limmodwnum+1,都不在的情况就用 w 减所有,计算这些需进行一些解不等式求区间长度的 dirty work,细节比较多

    • 最后还剩一个 w=2 的情况,此时 d 为奇数,直接就得到了 x+ya(modw),可以归到上述情况,注意特判求逆元的的地方

时间复杂度 O(TlogV)

C. 不朽之蜍

怎么做过和它 这么类似的题 还能不会的?

我不太会从这个题上调整最后一轮,就直接考虑 minmax​ 容斥

E(maxi=1nti)=T(1)|T|1E(miniTti),由于每张牌等价,E(miniTti) 只和 |T| 有关

枚举 |T|=x,则每一轮相当于碰到这 x 张牌和给出的 m 张牌就会停下,此时非常好的事情是每一轮都等价了,没有讨厌的最后一轮,只需求出一轮中期望消耗的步数乘上期望轮数

先求出一轮停下前期望抽出的卡牌数量 fx

fx=i=1nxP(抽出牌的数量i)=i=1nx(nxi)(n+mi)=i=1nx(n+mim+x)(n+mnx)=(n+mm+x+1)(n+mnx)=nxm+x+1

再考虑期望进行的轮数,某一轮结束时有 xm+x 的概率结束,mm+x 的概率继续下一轮,因此期望进行 m+xx

答案为 x=1n(1)x1(nx)m+xx(fx+1)

时间复杂度 O(n)

D. 大战杀马特

去年我绝对做过这题,但怎么最后 15 min 才想起来当时自己的做法啊……

为什么感觉去年这时候学的东西都离我而去了,是我记性差又不复习还是当时根本就没完全弄清楚呢……

考虑只有一次询问的做法,把每个数后面最小的数找到,每个数此时代表的最优点对放入堆中,每次取出堆顶,用主席树维护每个点此时后面没被它选的最小的数,进行单点修改,区间查询

多组询问的瓶颈在于我们不能把区间内每个数初始都这样做

那就再用一棵线段树,维护区间内最大的 alar,这个类似于最大子段和的维护,维护区间内最大值,最小值,最大点对即可

初始堆里只有全局的最大值,每次取出堆顶 (x,y)

  • 如果它来自全局,则把以 x 为左边的对用单组询问的方式,给它一棵主席树维护,把此时以 x 为左端点的最优对塞入堆中,并且为避免重复在全局的线段树上清空 x 位置的最大值
  • 如果 x 已经被单独拿出来了,那就直接在主席树上修改,并查询新的最优点对放到堆中

这样复杂度为 O(nlogn+klogn),空间复杂度 O((n+k)logn)

题解的做法是直接每次找 x[l1,r1],y[l2,r2] 的最优点对 (x,y),然后把区间拆分,拆分出的矩形要求两维重合或不交,这样能方便查询最优点对,复杂度相同,空间复杂度是线性

11.12

怎么做过的又不会了???一周内已经梅开二度了

C. SP4459 MUZIDA - Muzidabutur

朴素的 DP 是设 fi[1,i] 形成的本质不同子序列数(包括空序列)

转移第 i 个字符,它可以不加入也可以加在 1i1 形成子序列后面,但这里钦定子序列中每个字母是它最靠前的位置,因此如果原来子序列末尾在上一个与 si 相同的字符前,那么它不能在这里被计算,因此 fi2fi1flstsi1

|Σ| 很小,转移可以写成矩阵乘法,维护 fi1flstc1|Σ|+1 个值

矩阵中只有 O(n) 个位置有值,乘法可以做到 O(n2),用猫树分治优化可以做到 O(nlogn|Σ|2+q|Σ|)

继续想数据结构没有前途,继续挖掘矩阵本身的性质,发现它对角线上除了 A0,0 都是 1A0,0=2A0,c+1=1,Ac+1,0=1

矩阵代表的线性变换其实只改变了第 0 列和 c+1 列,用线性变换求前缀积可以做到 O(n|Σ|),如果能快速求前缀积的逆就 win 了

考虑转置原理,在使用前我们先将矩阵转置(注意区分这两个东西)把乘上逆矩阵也变成右乘

(ICD)T=(CD)TIT=(ABCD)T(AT)1(BT)1IT

先求前缀积,这两列的线性变换为 (X,Y)(2XY,X),先让 X2XY,再让 YX+Y2,得到 (X,Y)

求转置矩阵逆的前缀积,则是把线性变换反过来做,达到求逆的效果,注意矩阵转置后 A0,c+1=1,Ac+1,0=1,因此线性变换变成了 (X,Y)(2X+Y,X),求逆则先让 Y2Y+X,再 XXY2

回答询问时发现初始向量为 [1,0,0,,0],乘上前缀积的转置矩阵只需要矩阵的一列,最后只需要一个位置,需要转置矩阵逆的积的一列,可以存下这些列在线回答询问也可以将询问离线,复杂度为 O(q|Σ|)

总时间复杂度 O((n+q)|Σ|)

D. P10001 [集训队互测 2023] 优惠购物

假设一开始我们全部用金币购买,则会得到一些优惠券,最优策略是把它们全部代替金币用出去

但如果用了一部分优惠券后,花的金币就少了,可能会使得到的总优惠券数量减少

因此目标是安排花优惠券的方案使获得的优惠券数量减少的尽量少

xi 为第 i 个物品使用的优惠券数,si 为购买了 1i 的物品后剩余的优惠券数,初始 s0=m

si=j=0isj+ajxjcxj,唯一的限制是 si1xi

使用优惠券有三种情况

  • 第一种是 xiaimodc,则使用这一部分不会使后面获得的优惠券减少,是很优的
  • 第二种是整段 cc 个的使用优惠券,每使用一段即 c 张会使后面剩余的优惠券数量 1,产生了后效性
  • 第三种是整段使用完后的零散部分,使用了 <c 张即让获得的优惠券数量 1,是最不优的

因此我们按顺序贪心,先优先用第一种,由于它无后效性所以就从前往后贪心,xi=min(bi,si1,aimodc),逐步递推到后面

然后考虑第二种,由于每段都是用 c 张,产生的效果是令 s 的一段后缀整体减 c+1,所以越靠后的位置对后面的影响就越小,也就更优,从后往前贪心,每次尽量选更多的段,v=min(si1xic,bixic,minj>isj1xjc+1),实现时记录后缀的最小 sj1xj,每次操作后用后缀最小值减 v×(c+1)si1xi 更新后缀最小值

最后处理第三种,每段用的数量不确定了,因此先从尽可能多的开始用,相同数量还是优先用后面的,这样用到更多优惠券后才会使获得的减少

这一部分感性理解每次取大的很优,但感觉严谨证明有点困难啊……

ti=sixidi=min(ti,minj>itj1),则位置 i 最多还能用 min(di,bixi)

bixi 是定值,从大到小枚举它的取值 w,按这 O(n)w 分段,将 bixiw 的物品加入,每次取 di 最大的,发现 dii 增大单调不降,于是这里用大根堆维护加入物品的下标即可,如果 di 下一个段的 w 则更新并弹出堆顶,否则结束这一段

每次取对后面 di 的影响是区间减,用线段树维护 di,支持区间减,查询区间最小值

最后用得到的 xi 计算答案即可,时间复杂度 O(nlogn)

11.14

MX 模拟赛,被 T1 眼瞎题读错给干爆了

2025 -- 炼石计划 NOIP -- 多校联测专项

A. 邻间的骰子之舞

现在觉得这题也没那么难,但为什么我被硬控了那么久(

发现每次复制粘贴一次长度 ×2,因此最多复制 O(logn) 次就行了

一开始我想贪心,每次取复制还是粘贴中性价比最高的,但发现这个贪心假完了,没有前途

尝试 DP 写个暴力,设 fi 表示有 i 个字符的最短时间并钦定下一次操作是复制这个串,转移则枚举粘贴次数 jfi+x+jyf(j+1)i

初始 f1=0,我们突然发现字符串长度每次都是成倍数增加,可以写成每次粘贴次数 +1​ 的乘积

考虑枚举复制次数 m,此时想让粘贴次数最少,设第 i 次复制后粘贴 ai 次,问题被转化为求要使 i=1mai>n 的最小 i=1mai

二分答案,设 i=1mai=p,根据经典结论和一定的数要使乘积最大平均分配最优,直接 O(m) 算一下即可

复杂度 O(log3n)

但是为什么是长度 >n 不是 n,为什么是长度 >n 不是 n,为什么是长度 >n 不是 n……

[数据删除] 出题人往每个 subtask 内塞一个刚好卡到 n 的 corner case,直接 1000

有一种 whk 数学填空题看掉条件的美感

C. 勾指起誓

从最初的转化就已经错完了……

直接设 fS 表示当前淘汰了集合 S 内的人计数没有前途,枚举子集 T 计算贡献的地方有形如某些数必须放在一个后缀中的限制,然后这里的贡献非常复杂,还有对每对 TS 计算 TUUSU 数量的问题,实在是很复杂

不如转化一步,「注意到」一个题问多余一次是没有用的,那么每次选一道没有问过的题可以看作随便选一个,那么经过 n! 种问题顺序后集合 S 中人留下的概率和每次随便选一个问题问,问无限次后 S​ 剩下的概率相同

那我们求出概率就能求出最后剩下 S 的方案数

集合之间的转移就可以看作转移图,每个点除了连出自环外就形成了一个 DAG

发现 S 一定转移到它的一个子集 T,朴素做是 O(4m/3m)

转移形如 fScS×gTfST,其中 cS 为与 S 有交但不是 S 超集的答对人集合数量,即为 S 不是自环的出边数量,可以用高维前缀和与后缀和计算,gT 为答对人集合为 T 的数量

抛开题解说的,发现这是与卷积!可以用 FMT 做,过程就是一遍高维后缀和一遍高维差分,但很不好的是它是半在线的,从 popcount 大的转移向 popcount 小的,所以我们强行分 m 层转移,强行离线了属于是(

复杂度 O(m22m),用写科技可以做到 O(m2m),但我不会

D. 第八交响曲

谁爱写 双调排序 谁写,它在计算机可无限并行的情况下做到 O(log2n) 排序,这题就是它的板子题,但为啥挺多人过了这个科技(

11.15

A. AT_codefestival_2016_qualA_d マス目と整数

这题的颜色经过了一系列变化,但我还是不理解为啥放 T1 啊?可能是我做法太复杂了

观察到若固定第一行第一列,每个格子 Ax,y 可以表示成 Ax,1+A1,yA1,1

进一步的,随便固定格子 Aa,b 和它所在行列,则每个格子 Ax,y 可以表示成 Ax,b+Aa,yAa,b

最后要求 Ax,b+Aa,yAa,b,因此求出 a 行,b 列的最小值

选第一个给出的格子为 (a,b),然后可以列出一系列方程 Ax,b+Aa,y=bi,对每个连通块选一个代表元,可以推出所有值,如果连通块中有给定值则判一下是否无解,若有解则能推出连通块的所有值

否则设代表元为 x,由于图是二分图,行和列其中一个形如 x+v1,另一个形如 x+v2,分别求出最小的,和为 v1+v2

假设一定确定元素中行中最小的是 r,列中最小的是 c

r+cv1+v2 时,不论 x 怎样调整 v1+v2 始终取最大的最小值,v1+v2Aa,b,否则 r+cAa,b

题解好像直接把选的那行那列放到网格外了,就用了带权并查集维护?好像这才确实是 T1(

B. CF883D Packmen Strike Back

二分答案,转化为有一些点处有可以向左或向右覆盖的线段,问能否覆盖整个区间,用 Lanterns 这题的做法即可,复杂度 O(nlogn)

C. 字符串距离

我向来不会搜索题(

d 很小,考虑从第一个字符串的基础上调整,设当前已经调整了 i 个,找到此时跟当前串差异最大的串 x

  • 如果差异 dd>di​ 则无解
  • 如果差异 dd 则说明找到解,退出
  • 否则一定要把某一个不一样的位置调整成 x 的字符,直接枚举那个位置为 p,修改后递归搜索,注意一个个枚举 p 复杂度最高是 (2d)d_,这里为使复杂度最优,直接 (2dd) 枚举整个要修改的集合,实现上记录上一次修改的串和位置,如果它还是不满足条件就从上次位置后面开始枚举

这样复杂度最大的情况就是卡满 d 层,那每层就是 d+1 个不同位置,复杂度 O(n(d+1)d)

D. 独立集

将无向边看成从编号较小的往编号较大的点连的有向边,则图形成 DAG,一条关键路径就是从入度为 0 的点到出度为 0 的点的路径

路径长度都不是 k 倍数,考虑按 modk 相关的分类

然后设 Sxx 处到入度为 0 的点路径长度 modk 的取值集合,则所有 Sx 都不是全集,否则取 x 到出度为 0 节点的任意一条路径,都能找到一条路径跟它拼起来长度为 k 倍数

这里存储的路径长度先按边数算,令每个 x 的颜色为 Sx 中第一个后一个数不存在的数的后面不存在的数(k1 的后面是 k),这样入度为 0 的点颜色均为 1 ,由于对于 xySx 中每个元素 +1 会转移给 Sy,因此 x 的颜色一定在 y 中存在了,没有相邻点颜色相同,且保证每个点都能找到这样的颜色

维护 S 集合可以用 bitset 优化,复杂度 O(kmw)

但是我们有线性做法,考虑上面维护出了整个集合是很浪费的,我们只要找到任意一个集合中的数满足后一个数不存在集合中就行了

于是直接让入度为 0 的点颜色为 1,每个点看它的前驱的颜色中哪个的下一个不存在就行了,这样的颜色一定能找到,因为每个点的颜色代表一定存在一条从起点到它长为 colxmodk 的路径,如果找不到则说明前驱包含了 1k,与假设矛盾

时间复杂度 O(n+m)

11.16

B. 数据结构

怎么降智了(

放置的球一定形成若干棵子树,依次从下往上放

如果一个球放在 1 号点,它会先滚到子树内最小值的地方接着往它子树内的最小值处滚,直到走到某个叶子,把球放在那里

不断的把球往 1 号点放,则每个点有一个被占领的时间,可以像这样递归预处理出占领顺序

关键的性质是如果树上有些点已经有球了,也不会影响其它点被占领的顺序

因此每次我们在 u 子树内找到没被占领且占领顺序最靠前的点,可以用线段树维护,放置球,去掉 u 处的球则倍增找到它最顶上的有球的祖先

总复杂度 O((n+q)logn)

11.18

A. P9195 [JOI Open 2016] JOIRIS

Construction is too hard for me : - (

下标从 0 开始

消除成功的最后一步,一定是所有列的高度都相同,如果所有列高度 modk 都相同,那么就能不断将某些列 +k 达到目标

于是目标就转化为让所有列高度 modk 相同

放置横着的方块,可以让它覆盖的列 modk 的高度相对其它列 +1,只要放置后把其它列全部竖着放方块直到全部不低于横着方块,此时这一整行消失,其它的少 1 而被覆盖的没动

区间加考虑差分数组 bi=aiai1,发现每次形如 bibi+1bi+kbi+k1,每个下标 modk 的同余系中差分数组和不变,而最后我们想让除了 b0bnb 均为 0

有解的充要条件就出来了,i0inmodk,jmodk=ibj=0

构造方法就是先倒着把所有 imodk=0bi 清零,全部放到 b0 处,再从 b1 处开始向后把所有 b 清空,若有解则一定可以清零

所以这样最多只会操作 O(n2+ai) 次,可以通过

C. 图的周期

怎么是论文题……

转化题意为

在有向图 G=(V,E) 中,如果存在一组整数 p,k,使得对图上任意两点 x,y 和任意的 tk,存在一条包含 t 条边的路径 xy 当且仅当存在一条包含 t+p 条边的路径 xy,且以 p 为第一关键字,k 为第二关键字,上述整数对是最小的,则称 p,k 分别为 G​ 的一组周期和幂敛指数

考虑一个强连通分量,那么 p 为强连通分量中所有环长的 gcd,计算 gcd 则取图的一棵生成树,设一条非树边为 xy,w,则只用对所有 depydepx+wgcd​ 即可,证明见论文了

整个图的周期显然就是各个强连通分量周期的 lcm

p 的时间复杂度为 O(n+m)

k 没有什么直接的方法,但求出 pk 可以二分,如果 Ax=Ax+p 说明 kx

那么回到最初的矩阵定义,倍增 k,用 bitset 优化矩阵乘法的过程,复杂度 O(n3logVw)

11.19

又是不会 T1 的一天,哈哈哈

A. 正在生产三叶虫

手玩样例或推一下得出 ai=n1+[ain1n+1]+[ainn]

将每个数减去 n 并整理式子,得到 ai=[ain1>n][ain<n]ai 只会为 1,0,1

此时将 modn 相同的为一组,「注意到」为 1 的会对下一组 modn 的下一个产生 +1 的贡献,为 1 的会对下一组的同一个产生 1 的贡献,可以看成 1 不断向右走,1 原地不动,1 撞到 1 就两个都消失

对序列的 1,1 做括号匹配就能知道是哪两个相撞了,注意这里它们在环上走,要把环复制一遍接在后面,只加入第一遍中的 1,第一遍开头没有匹配的 1 要在第二遍的开头寻找第一遍结尾的 1 匹配

计算出每个点的相撞时间后就能知道它在哪几轮存活,查询时找到询问位置对应的最开始的 1 的位置,注意这里 1 到序列末尾后会空一轮,下一轮再从开头开始走,出现位置以 n+1 为周期,有一些细节要注意

时间复杂度 O(n),细节很多

B. 相信武魂真身

偶环和奇环分开讨论

  • k 为偶数时要求 i=1kci>k2,即 i=1k(ci12)>0,发现满足条件的偶环中一定有一条边两端点权值和 0,那我们不如直接取这条边,因此判断很简单
  • k 为奇数时要求 sumi=1kci>k12,即 i=1k(ci12)>12,记录新点权 ai=ci12,此时进入这里判断时每条边 (u,v) 的端点 au+av0

把点权分摊到边权上更好观察性质,设 (u,v) 的边权 w=au+av2,则一个环原来的点权等于现在的边权,发现所有边权均非正,想让奇环的总权值尽量大,直接枚举某个在环上的点 x,将一个点 i 拆成两个 (i,0),(i,1) 分别表示 ix 经过了偶数条、奇数条边的最长路,求出 (x,0)(x,1) 的最长路

注意找到路径后有可能不是简单环,但我们直接舍弃就可以了,因为所有边权非正,多走边只会让环的权值越来越小,考虑权值最大的奇环,一定是简单环,那它就一定能被找到,实现上找到路径后随便取它中间的一个简单环也可以

复杂度 O(Tnmlogm)

C. 轻舟已过万重山

把异或用形式幂级数刻画,Ai,j 代表 xAi,j,要求的是 pi=1nxAi,pi 中哪些项的系数不为 0

使用 FWT 优化异或卷积的计算,对每个位置做 FWT,异或卷积计算时就能变成对应位置相乘,要求的则是矩阵的积和式

积和式不好求,让初始的系数不是 1,而是一个随机数,这样我们直接求行列式,判断哪些项系数不为 0 即可

正确率分析感觉不好说,把每个位置的系数看成多项式的 n2 个元,做行列式得到 n2n 次多项式,最后判断 n2 个多项式是否为零多项式,可以用 Schwartz-Zippel 定理,单个误判的概率为 nV,所有都正确的概率是 (1nV)n2,总之还是挺高,但把积和式化为行列式的一步的正确率不会分析

总之感性理解它很对就是了(

D. Three Gluttons

从每个序列都固定了它们要取哪些数及其顺序,计算摆放方案开始判断

A,B,C 三个序列分别取了 a,b,c 中的数,那么要求是对于所有 ciji,aj,bjC 序列中 ci 后面,对 ai,bi 同理,但由于 C 已经满足要求了,可以简化条件为 ji,bjA 序列中 ai 后面,ajB 序列中 bi 后面

C 的种类计数先不考虑 A,B 的条件,倒着看,an3,bn3cn3 后面,有 1×2 种放法,an31,bn31cn31 后面,有 4×5 种放法,依次类推,发现数量就是 i=1n3(3i1)(3i2)

于是问题转化为了对 a,b,c 计数,最后乘上上面的方案数即可

考虑用 DP 依次确定,设 fx,i,j 为考虑了 a,b,c 中前 x 个数,当前 axAibxBj 的方案数,从 fx1,i,j 转移过来,要求是 B1j 中不能有 AiA1i 中不能有 Bj

再考虑 cx 的选法,要求 cx 不能在 A1i,B1j,ax+1n,bx+1n,cx+1n 中出现过,ax+1n,bx+1n,cx+1n 三者无交,与 A1i,B1j 也无交,只需要用 3x|A1iB1j|,可以预处理出 gi,j=|A1iB1j|

用前缀和优化转移,复杂度 O(n3)

11.21

C. Alter//Strife

博弈论,发现如果知道了已经选出的数的 gcd=g,那么选出的数一定在 g 的倍数中,不是 g 的倍数才会造成 gcd 变化,且它们一定没选, 所有除了 g 只需要知道选出数的个数就能刻画整个状态

f(x,g) 为当前已经选了 x 个数,gcd=g 时,考虑剩下的数是否先手必胜,转移则枚举下一次取了哪个数,计算概率同理,设 g(x,g) 表示考虑剩下数时先手赢的概率

这样写会发现跑的飞快,但仔细一想复杂度是什么,如果每个数有 d(A) 个因数,有 n 层,转移是 O(n) 的,岂不是复杂度 O(n3d(A))

精细分析,换种角度,对每个 g 分析有多少个 xx 的个数就是 g 的倍数在 ai 中的个数,再次反过来考虑,每个 ai 对自己的因数有 1 的贡献,所以总状态数是 O(nd(A)) 的,复杂度 O(n2d(A))

D. P6557 Yesterday Once More

转化为放置 1×k,k×1(k>1) 的矩形的方案数,考虑插头 DP,记录轮廓线是否伸到下一行,前一个格子是否有伸出来的插头,把一行某些格子设置为障碍,就是把从前从后的两个 DP 数组拼起来,这里由于必须是插头对插头,因此每次询问只用枚举 O(2m)

11.22

C. 傳自我的手機

我们要对每个连通块维护多项式的乘积,和所有连通块多项式的和

注意到模数很特殊,u,v 都很小,如果把 x 写成 ku+b 的形式,多项式要求的点值恒为 u,则次数 v 的项都不用维护

考虑对 0u1 的每个 b 都求出对应多项式,此时 b 就跟 ai 看成一个整体,维护多项式即可

删边操作和修改点权都可以用线段树分治维护,看成加边和加入点,复杂度 O(nlognuv2)

posted @   KellyWLJ  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示