集训队互测2023

个人觉得质量很高的题用红色标记。

D1T1

考虑贪心,设 si 表示操作完第 i 次剩的优惠券数量,xi 表示第 i 次用的优惠券数量,那么充要条件就是 si1xi0

然后发现我们会获得一些优惠券,我们每使用一些优惠券,会少获得一些优惠券,我们要使少获得的优惠券数量尽可能少。我们考虑在一个物品上增加花的优惠券数量,分为以下三个阶段。

1、花费 [0,aimodc] 的优惠券,此时代价是 0

2、花费 c 的优惠券,此时代价是 1

3、花费 [0,c1] 的优惠券,代价是 1

显然第一种优于第二种,第二种优于第三种。

考虑按这种顺序贪心,第一种因为不需要代价,只要优惠券够用就直接做就好了。第二种可以算出第 i 个最多减少的优惠券数量是 min{bixic,si1xic,minj>isj1xjc+1}×c,记录后缀 min 即可。第三阶段可以从大到小枚举 c1,c2...1,然后式子和上面类似,时间复杂度 O(nc)

我们设 deli=min{bixi,ti,minj>itj1},ti=si1xi,发现我们做的实际上就是每次找到 deli 最大的 i,将 xi 加上 deli,并修改 titideli,tj[j>i]tjdeli1。下面我们可以观察到 min{ti,tj1} 具有单调性,所以我们可以按照 bixi 排序,然后每次加入若干 bixi 相等的位置,处理掉所有 minbixi 的位置,此时能取的是可行集合与一段后缀的交集,不难发现取可行集合中最大的最优(最有可能成功),所以我们可以用堆来维护可行集合,每次修改和查询用区间加区间求 min 的线段树解决。时间复杂度 O(nlogn)

D2T1

fi,j,k 表示前 i 个位置,有 j 个本质不同的元素,存在 1,2 情况的最大元素是 k 的方案数,转移显然。最后再乘上一个组合数选出那些本质不同元素即可。时间复杂度 O(n4+nq)

D2T2

首先发现条件等价于 ffi+fj=fi+j。继续观察性质,令  ij 表示 fi=fj ,那么对于任意 i,jfi+fji+j,所以,若 i1i2,j1j2i1+j1fi1+fj1fi2+fj2i2+j2,所以如果 iji+1j+1,所以合法序列一定是由一段前缀 0,1,2,3... 和一段循环节的不断循环构成的,依靠这个性质进行暴搜可以获得很高的分数。

p 是最小的满足 fp=fq 的数。记循环节长度为 k=qp。分类讨论 f0 的情况。

f0=0 时,显然有 ifi。对于 0i<p,不存在 fj=fi,那么 fi=i。对于 pi<q,有 k|(fii),那么 ifi(modk)。可以发现,在此基础上,只要满足任意 i+jnfi+fjn,那么所有条件都合法。证明由 ifi(modk) 显然。进一步分类讨论,当 q1n2 时,任意两个出现的数都在 n2 之前出现,所以需要有任意 fin2 即可满足条件。当 q1>n2 时,不难发现当且仅当有 pi<q,fi=i 时满足条件。可以枚举 p,q 然后方案数即为 pq1 这些数填法的乘积,可以先枚举 k ,记录 ai 的后缀 min 做到 O(n2) 计算。 

f0>0 时,有 f0+f00+0,也就是 f2f0=f0。由于 f00 所以循环节从 0 开始,且 k|2f0。再次分类讨论,当 k|f0 时,有 f0k ,所以 kn2。类似的,可以证明任意 fin2。同样的,可以先枚举 k 然后处理后缀 min 把方案数乘起来 O(n2) 计算答案。

kf0 时,有 2|kk2|f0。所以 f0k2modk。又因为 f0+fii,所以 f0+fiimodk,所以 fii+k2modk。代入 i=k21,有 fk21k1,所以 k1n2。同理,也有 fin2。然后可以用类似的方法计算答案。时间复杂度同样是 O(n2)

D3T1

首先有一个套路 dp,设 dpi,j,k,l,m 表示考虑了 1i 的数,有 j 个连续段,上一个数在第 k 个连续段中,两维答案分别是 l,m 的方案数,转移枚举下一个填在哪里,可以前缀和优化为 O(n5),能通过 n100 的数据。

注意到这个 dp 并没有什么优化空间,考虑从容斥的角度解决问题,求出 fi,j 表示正排列中钦定 i 个位置,逆排列中钦定 j 个位置的方案数。然后再二项式反演回去。

i 个上升位置就表示我们有 ni 个连续上升段。依次填入 p1 的每个连续上升段,发现在 p 中的体现就是将每个数从小到大填进 p,所以任意时刻 p 中每个连续段被填入的是一段前缀。考虑设 ak,l 表示在填 p1 的第 k 个上升段时,p 中第 l 个上升段填入了多少元素,那么发现 k[1,nj],l[1,ni],且一组 ak,l 与一组 p 形成双射。

ak,l 计数,限制就是总和为 n ,且不能有一行全空或一列全空,考虑容斥钦定一些行列全空然后插板法再二项式反演回去即可。时间复杂度 O(n3)

D3T2

我在赛时写了一个期望复杂度 O(nnlogn) 的东西通过了 105 的测试点,这个东西就是找 B 个位置维护 1x 位置的边的并查集,每次加边加入至多 B 个并查集,查询的时候找到最近的并查集暴力加入期望 nB 个元素,用可撤销并查集实现。

赛后 Alan_Zhao 老师提出了一个严格 O(nnlogn) 的算法,个人认为这个做法很有启发意义就在此记录一下。考虑每 B 个询问定期重构这个图的点 Kruskal 重构树并预处理出重构树的倍增数组,询问的时候考虑 bfs,首先把 x 节点最浅的不超过 y 的祖先加入队列,每次从队列中取出一个点,然后将他的子树大小计入答案,然后遍历这棵子树内向外连的所有额外边(这个显然可以用 set 之类的数据结构维护),将这些额外边对应节点最浅的不超过 y 的祖先加入队列(如果他原先没有加入过),然后继续遍历,由于只有 B 个额外边,倍增和 set 的复杂度都是 O(logn) 的,所以总的复杂度就是 O(nnlogn) 的。

正解是 LCT,NOI 不会考。

D4T1

发现条件等价于每一时刻在里面的点不超过 m 个,然后发现当前加进去这一个显然要占一个位置,那么可自由支配的有 m1 个。首先让所有的都每次加入,考虑最多能减少多少代价。我们发现,如果一个 i 要节省掉代价,那么就需要 lstai+1i1 这段位置都被覆盖,这个模型显然可以费用流解决。

建图 (s,1,m1,0)(q,t,m1,0)(i,i+1,m1,0)(lstai,i1,1,wai) 跑最大费用最大流即可,SPFA 的复杂度是 O(q2),最多增广 O(m) 次,总的复杂度就是 O(q2m),因为常数比 std 的建图方式小所以可以通过。

D4T2

发现那一大堆条件就等价于与同一个交点相邻的同属于一个矩形的两段不同色,点边相邻的两块不同色,且边相邻的两块恰有一块无色这些条件。

然后手动模拟一下扫描线,大概就是遇到边界的话,直线相连的那一块变成无色,然后对角相连的那两块变成另一种颜色。所以我们发现,每当扫到一条边,那么对应的有色块一定都是同一种颜色,并且有色块和无色块一定是间隔分布,不然就会发生矛盾。也就是说,两条颜色带之间一定间隔恰好一段线,所以两条颜色带的颜色必须是一样的。因此在截断若干条颜色带时,我们要求这些颜色带的颜色都是相同的。所以可以考虑用扩展域并查集维护颜色的相同关系,这部分做法比较套路。

根据上面发现的结论,我们每次扫到一条边时,要把他截到所有线的颜色变成同一个未知数,区间推平操作显然可以用 ODT 维护。此处注意到 ODT 中维护的不再是一条线段,而是一个具有插头的点,只是为了方便描绘我们仍然用 (l,r,c) 的三元组来维护。每次就是需要把与左右端点相邻的两段 single 出来,注意不只是 split ,因为这里我们已经推平了一些段,而次数在边界位置会破坏掉一些推平关系,所以一定要把这一个插头单独拿出来。然后维护的时候就合并并查集,然后推平,扫到右边界的情况大同小异,注意到少了两个插头要合并对应的连续段即可。

D5T1

出锅/oh 虚空调试/oh

不过题目本身还是不错的。首先考虑 AC 性质的情况,这时候我们只需要维护当前的线性基对应 n 个位置的值,注意到线性基只会变化 log 次,每次线性基发生变化的时候暴力维护就是 nlog2n 的。注意到每次线性基是插入一个代表元素为 x 的数,然后我们发现,就是 ai 没有 x 这一位的时候需要把他插入,这里有一个观察,就是我们每一个需要变化的元素的变化是一样的!因为我们之前的部分肯定已经是最优情况,所以我们要尽可能消除插入这一位对后面的影响,体现在线性基上需要做的操作就完全一样,这样就可以把这一部分的复杂度变为 O(nlogn)

考虑有修改操作的情况,我们记 g(x,S) 表示 maxTSxTh(x,S) 表示 minTSxT,那么有 g(xy,S)=g(x,S)h(y,S),证明可以感性理解,也可以手动模拟这个过程就行。

那么我们每次修改的时候对于 g(x,S) 数组的影响就是后缀异或上 h(v,S),区间异或操作显然可以简单的用 logV 棵线段树维护,查询操作发现只需要异或上前缀异或和即可,也是容易处理的,这一部分的复杂度就是 O(qlognlogV) 的。然后我们考虑线性基发生变化的时候,仍然用上面的方式重构,把当前的 g 数组拿下来,然后修改需要修改的,重新建树,发现瓶颈在建树上,复杂度是 nlognlogV ,不能通过。

发现线段树的每个节点记录的信息有些浪费。我们用一个 int 类型变量记录了只有 O(len) 大小的信息。这里考虑一个 trick,我们认为记录的是一个矩阵,每一行维护了第 i 位的信息,考虑将这个矩阵旋转 90 度,那么我们每一行维护的就是每一位的信息在第 i 位是 0 还是 1,这样发现我们这棵线段树每个节点维护了 O(loglen) 的信息,主定理分析一下 T(n)=2T(n2)+O(logn)O(n) 级别的,这样就把复杂度降到了 O(nlogV+qlognlogV) 。维护的时候发现 pushup 就是手动模拟加法器,apply 就是手动模拟减法器(或者转补码用加法器),如果做过 THUSC2023 Day2 应该不会陌生,这部分都可以在 O(loglen) 时间内处理出来。 然后好像需要大力卡常才可以通过,可能是我写的比较丑。

D5T2

首先考虑 q=(1,2...n) 的情况,这时候我们发现充要条件就是极小值域连续段数 k,设 fn 表示有多少个 n 阶排列极小值域连续段数为 1,那么容斥第一段连续段的长度,有 fn=n!i=1n1fi(ni)!。令 F(x)=fixi,显然答案就是 ik[xn]Fi(x)

考虑一般情况,找到第一个满足 qi>qi+1i 记为 t ,那么显然 t 是一个分界点记为 xc,记 xc+1=t,那么 t 之后一定是每个单点一段,不然可以拆开一段合并第 cc+1 段会更优。另一个条件就是在 t+1t 之间只有 t+1 满足 qt+1<qt 并且 qt+1=pt,否则一定可以把这个分界点挪到上一个之前会变得更优。

假设已经知道 tt 那么答案就是 [xt]Fc(x)(tt1)!,前面的套用第一种,然后中间的除了最后一位随便排,后面的不能动,然后 c=k+tn1 可以容易算出来,复杂度 O(n3)

D6T1

注意到有很多状态是被偏序掉的,如果在某一时刻一组 A>A,B>B,那么 (A,B) 存在时 (A,B) 完全没有用,考虑用一个单调队列存下来有用的,复杂度 O(n3)。再发现有的东西可能被两个共同偏序掉,具体来说就是对于任意 (x,y),有 (aj+x)(bj+y)>(ai+x)(bi+y) 或 (aj+x)(bj+y)>(ai+x)(bi+y) ,那么 (ai,bi) 完全无用,再把这些偏序掉复杂度就是 O(n2) 了。具体实现类似斜率优化。

其实因为数据随机,按照 aibi 贪心然后小范围调整就是对的。

D6T2

首先考虑 w={0,1} 的情况,我们把所有的路径提取下来,按照字典序排序,不难发现最后的答案就是选取路径的 len 之和减去相邻两两间 LCP 长度。 考虑设计一个朴素的 dp,设 dpi,j 表示当前选了 i 的集合,上一个是 j 的最大答案,转移显然,时间复杂度 O(2nn4),不能通过。考虑优化这个 dp,注意到排序后 lcp(i,j)=mink=ij1lcp(k,k+1),设 dpi,j 表示当前选了 i 的集合,上一个到当前位置的相邻两两 LCP 的最小值为 j,每次下传 dp 值并进行更新,时间复杂度 O(2nn3),可以通过对应的部分分。

然后考虑 w={0,1,2} 的情况,我们枚举每条路径的情况,注意到这里最大的问题是路径数变成了 O(2n) 级别的,所以直接进行 dp 就是 O(4npoly(n)) 的。但是这个真的是上界吗?注意到对于一条长度为 x 的路径,它最多有 2x 种不同情况,他每次更新的时候显然只会更新他的边集的超集,这个大小是 2nx1 的,所以每条路径更新的复杂度是 O(2n) 的。所以使用滚动数组,就无需继承上一次的 dp 值可以直接更新。那么现在的瓶颈就变成了下传的部分。同样的,下传的时候也可以只下传会有变化的位置,具体的说,我们暴力枚举上一个选的是谁,如果它在这一个位置的 LCP 长度发生变化,我们就暴力更新它的超集,而此刻的原始 LCP 也是确定的,所以也不需要枚举这个。进一步的,在这个位置 LCP 发生变化的一定是一段连续的区间,所以也不需要进行二分找到变化位置,只需要从后向前枚举即可。注意到每一个的 LCP 只会变化 O(n) 次,所以这部分的复杂度也是 O(2nn3) 的,这样我们就完成了第一问。

考虑第二问,用哈希表记录 pre 数组是一个比较显然的做法,但是常数上很明显过于爆炸。我们考虑用一个可回退数据结构(即栈)来实时维护 dp 值的变化。每次 dp 值发生变化时,我们就把这次变化压入栈中。输出答案时,我们每次回退到当前位置,判断当前状态能否被选入答案,然后加入答案集合即可。仔细分析可以分析出空间复杂度(即变化次数)是 O(2nn2) 级别的,所以空间也是够用的。这样,我们就以 O(2nn3) 的时间复杂度 ,O(2nn2) 的空间复杂度解决了这道题。

D7T1

注意到每个点至多会被向前移动一次,而这一次它就到达了它的目标点。所以,我们考虑以这种方式计算每个点的贡献。首先有一个观察,每个点如果前面有比它小的点,那么在它向前移动之前这个比它小的点都在它之前。因为如果比它小的点向后移动要么不超过它,要么会带着它一起走。考虑另一种情况,它后面有比它小的点,记第一个为 mn,那么,如果是排列,只要存在 i>mn,ai>ax ,那么它就会被交换到 i 的位置,因为比它大的点一定会先被移走,然后它前面另一个比它大的点(或它自己)就会递补到这个位置,直到最后它自己递补到这个位置。然后考虑不是排列的情况,发现它后面比它大的点肯定会先它移走,那么到最后,能取代这些点的要么是 x 本身,要么是 x 之前其他满足 ai=axi。所以,不难发现,此时充要条件就是满足 i>mn,ai>axi 数量 > 它前面和它相等的数的数量。形式化地说,对于一个点 x 如果要产生贡献。那么条件就是存在 i<x,ai<axp=i=1x[ai=ax],q=i=mn+1n[ai>ax],pq。直接实现时间复杂度 O(n2logn),期望通过 n104 的数据。

注意到第一个条件显然是容易维护的,对于第二个条件,可以枚举 p 的大小,对于每个 p 也对应一个二维矩形,然后就可以转化为一个二维数点问题。矩形个数是 numi2 个的。我在赛时实现了这个做法并发现出题人没有卡,可以获得 100 分。

考虑更正经的做法,把上一个做法的正序扫描线变成倒序扫描线,每次新加入一个点,这个点在这一时刻对应的矩形是容易通过类似线段树二分在 O(logn) 的时间内求出。考虑其他点的矩形的变化,对于 aj>ai 的点,显然此刻变成了满足第一种条件,并且每个点只会发生一次这种变化,容易维护。对于第二种,貌似并没有好的维护方式,还是只能 O(numai) 地暴力修改。但是,我们注意到,每一个对应的合法 r ,变成了它上一个对应的合法 r ,也就是说,中间的部分实际上没有改变。具体的,假设我们原来 lk<lk1<...<l1 对应的分别是 rk<rk1<...<r1 ,需要加入 lk+1,那么改变完之后 ,lk+1 对应 rklk 对应 rk1l2 对应 r1l1 对应一个新的数,所以,我们相当于只需要新加入一个端点为 l1 新对应的数的矩形就行了。这个也是容易通过线段树二分找到的。时间复杂度就可以做到 O(nlogn),可以获得 100 分。

D7T2

首先可以简单的容斥,设 fi 为将这棵树进行合法的 i 染色的方案数 ,那么有 ansn=i=1nCnifi(1)nin!,可以卷积 nlogn 求出。考虑链的情况,按照顺序染色,发现每个点的限制条件就是它不能和前面的 ai 个点同色,因为是链,所以可以保证前面这 ai 个点不同色,所以方案数就是 (mai)。这个东西可以看做一个关于 mn 次多项式,通过分治 NTT 求出。然后查询每个点值就可以看做多项式多点查值,复杂度都是 O(nlog2n)

然后考虑树的情况,事实上,链的最好的性质就是保证了前面的 ai 个点不同色,所以可以简单计算方案。那么树是否也能钦定一个顺序,让它也有这个性质呢?事实是可以的。我们考虑以 1 为根,按照 dep 排序计算贡献,就是满足条件的。设前面的集合为 S,我们就需要证明对于任意 v1,v2S,dis(v1,v2)<k。显然有 dis(v1,x)<k,dis(v2,x)<k。设 v0=lca(v1,v2),那么当 xv1 不在同一子树时,dis(v1,v2)<dis(x,v1)<k。又因为 v1,v2 不在同一子树,所以 v1,v2 总有一个能完成上面证明。所以,我们就有了这样的关键性质:钦定 dep 从小到大,每次加入时 S 中所有点的颜色一定不同。如果边权不为 1 ,就把 dep 变成带权 dep 就行了。暴力实现的复杂度是 O(n2)

考虑快速计算 |S| 的大小,建出原树的点分树,然后找到当前点在点分树中的位置,对于点分树中它的每个祖先,用树状数组维护权值,每次就是树状数组单点加前缀查询,可以简单维护,时间复杂度 O(nlog2n)。对于 w 不为 1 的情况,考虑把树状数组换成平衡树,一样可以做到 O(nlog2n)

D7T3

贪心,考虑怎样操作最优,下文中记最小的字符为 a。首先形式化地给出贪心的方式,记 f(s1,s2,...sm) 表示将 s1,s2...sm 这些串进行重组后的答案。其中存在一个最大的 k 使得 s1=s2=...=sksk+1...sm。那么 f 的转移如下:

1.k=m ,此时 ans=s1+s2+...sm

2.mkk,此时最优情况显然是 f(s1+smk+1,...,sk+sm,...smk),这些大的显然是越往前放越优,大的放在相对靠前位置显然优于更小的放在相对靠前的位置。

3.mk<k,此时和上面类似,不同的是前面一部分 s 后面不能接东西了。也就是 f(s1,...sk(mk)+1+smk+1,...sk+sm)

需要维护两个串是否相等,然后拼接两个串,暴力实现容易做到 O(n2logn)

考虑优化,注意到我们第一次变化完,所有串要么是一个字符(要么全是 a 要么全都 >a),要么是  a 开头的两个字符。发现我们比较两个串 sa1+sa2+...+sap 与 sb1+sb2+...+sbq 的大小,就等价于比较 [rka1,...rkap] 与 [rkb1,...rkab] 的大小。我们设 saksbk,如果 ak 不是 bk 的前缀,那么显然可以正确比较。否则 ak 一定是单独一个 a,那么所有的 s 都以 a 开头,那么 sak+1 的第一个字符是 a,显然小于 sbk 的第二个字符(不是 a),所以上述结论成立。

然后我们就可以用链表维护拼接,每次实时更新 rk 数组。发现如果进行第二种操作,用 O(k) 的时间复杂度使得长度减小了 k,如果进行第三种操作,用 O(k)<O(len) 的时间复杂度,使得下一次进行第三种操作的时候的长度是 min{2(lenk),len(lenk)}23len,所以这部分的时间复杂度总和是不超过 O(nlogn) 的。所以总的时间复杂度就是 O(nlogn)

D8T1

发现容斥和直接 dp 都没法很好的解决问题,考虑组合意义。首先考虑 k=1 的情况。考虑一个组合意义,有 a1+a2+...+an 个球,第 i 中颜色的球有 ai 个,将他们排成一排,ri 为第 i 中颜色的球最后出现的位置,考察 r1<r2<r3<...<rn 的排列个数,不难发现合法的排列占总排列数的 aisi 的。

另一方面,我们假设已知 a 中的元素,只考虑排列顺序,那么对于任一将这些球排成一排的方案,总存在恰好一个排列使得 rp1<rp2<...<rpn ,那么这种方案会对 ap1...apn 这个排列产生 1 的贡献。那么也就是说,每个将这些球排成一列的方案,都会对恰好一个排列产生一个合法排列的贡献,也就是说,对于每个 a 的排列顺序,他们合法排列的数量和和总排列数相等。形式化的,令 g(a)=aisi,对于已经确定 a 中元素的 ag(a)=1。然后此时 f(a)=g(a)ai,所以 a 的所有排列的 f 之和是 1ai,直接背包即可。

对于 k=2 的情况,由于多了 a1 的贡献,我们考虑直接枚举 a1。对于前面的分析,我们现在发现,只有 p1=1 的排列才会产生贡献,也就是说 r1 最小的方案才会对其中一个排列产生贡献。而我们要统计的,就是 r1 最小的排列数除以总排列数,然后再乘上 i=2n1ai。考虑如何计算第一部分的答案,容斥,钦定一个集合 TS 中的 r<r1 ,统计这个方案数分成三部分。先将 T 中相对顺序钦定好,令 sum=xTx,这部分的答案为 sum!xTx!。然后再把 a1 个颜色 1 插进去,方案数为 (a1+sum1)!sum!(a11)!1 是因为要钦定 r1>r。 然后再把其他的加进去,方案数为 (ai)!(sum+a1)!iS,iTai!,三部分乘起来再除以总方案数就是 a1sum+a1,再乘上容斥系数就是答案。这样就解决了 n=m 的情况。

对于 nm 的情况可以考虑 dp。设 dpi,j,k 表示考虑了 1i 的元素,当前选进 Sj 个,选进 T 的元素和为 k 的容斥系数总和,注意这里的容斥系数同时还乘上了 S 中元素的 1x。转移的时候枚举当前这个元素的状态,处理容斥系数的变化,都比较容易。加上枚举 a1 的时间复杂度为 O(n5)。注意到我们并不需要枚举 a1,只需要在 dp 数组中再加一维 0/1 表示是否选过 a1 了,选择当前数 a1 对应的转移就是把最后答案中分子上的 a1 直接乘进去,原来的分母是 a1+k 的形式,现在我们只需要把 a1 加进 k 中,注意此时并不代表 a1 加入了 ST 集合,最后统计答案即可。时间复杂度被优化为 O(n4),可以获得 100 分。

D8T2

首先对于 k2n2 的情况可以暴力。我们设 i 的最优比率环为经过 i 的长度/环长最小的简单环。对于 k>2n2 的情况,有这样的关键性质:走法一定是从起点走不超过 n2 条边,然后绕一堆最优比率环,再走不超过 n2 条边。证明感性理解。大概就是 n2 条边有 n 个环,就可以组成任意 siz 的环,所以能被替换为若干最优比率环的样子。然后剩下的事情就是模拟这个过程。首先处理出 fi,j1 开始表示走 i 轮到 j 的最小代价,预处理 f 和最小比率环,然后枚举转折点和环长,找到最后还剩下第一个不超过 n2 的步数就是接下来需要走的,然后用这个东西初始化 gi,j 数组,然后再类比 f 的递推去递推 g 数组,最后 g0 就是答案。时间复杂度为 O(n2m)。我尝试实现但是不知道怎么规避高精度被卡了空间,所以觉得太难写就没补。

D9T3

为什么永远做不出来这种从上到下 dp 的题/oh 为什么永远做不出来这种从上到下 dp 的题/oh

首先可以预处理出来以每一个点为根子树的拓扑序种类 dpu=(sizu1sizv1...sizvk)dpv。然后考虑枚举 x ,然后设 fu,i 表示以 u 为根的子树,只考虑子树内部拓扑序,不考虑与外界的联系和外界拓扑序,有 i 个排名在 x 之前的方案数。转移就是 fu,i+j=tmpifv,j(i+jj)(nowsizuisizvj),如果已经访问过 x 节点那么 nowsizu1,因为 x 不算在可以任意排列的里面。时间复杂度 O(n3),并且看起来就很没优化空间。

发现上面的东西慢很大原因是因为要枚举 x ,所以在树形背包的复杂度上又乘了一个 O(n)。考虑反过来,从上到下 dp。我们设 fu,i 表示关键点以 u 为根的子树内排名为 i(此时还未钦定关键点),已经确定了子树外的拓扑序和子树内外的相对排列关系,未确定子树内的拓扑序的答案总和(不是方案数)。注意到这个状态和上一种做法的状态是完全相反的。这个状态显然有初值 f1,i=bi。考虑转移,既然状态相反,转移基本也是相反的。转移是 fv,k+1=fu,j+k+1(j+k1j1)(sizu(j+k+1)sizusizvj)xsonu,xvdpv(sizxsizx1...sizxk)。然后第 x 个点的答案就是 fx,1dpx。转移复杂度分析类似树形背包为 O(n2)

D10T1

被卡在了莫名其妙的一步上。

首先需要观察一些性质,可以用一棵二叉树来刻画合并过程,合并书 u,v 时,新建一个节点 x 作为 u,v 的父亲。然后考虑计算贡献,重量部分的贡献显然可以用 depiwi 刻画。不难发现,如果确定了所有的 depi ,那么显然对于 dep 从小到大,w 从大到小就是最优的情况。所以,只需要关心树的形态即可。再考虑磨损值部分的贡献,可以发现,对这棵树进行长链剖分,那么除去根节点所在的长链之外的集合记为 S,这一部分答案就是 pathS2len(path)11 最后再减掉,下面令这一部分贡献为 pathS2len(path)

然后考虑如果已经确定了 d1,d2,...,dn,如何配对能够使得答案最小。不难发现,我们的答案是每条长链的长度对应的 2len,每次选择两个配对能做的就是截停一个让他在此处作为长链,不在更长的时候作为长链,那么肯定是将更长的截停更优,也就是说,要按照子树内最大 dep 排序之后相邻两两配对最优。接下来考虑如何计算贡献,手玩一下可以发现,将每一层的节点从 0 开始标号,第 i 个节点如果是叶子,它产生的贡献就是 lowbit(i),这样就已经可以形式化地刻画贡献了。

接下来考虑 dp,首先可以设计一个 dp。设 dpi,j,k 表示从上到下第 i 层,当前层有 j 个节点,一共填了 k 个叶子,转移枚举这一层填几个叶子进来,时间复杂度 O(n4),期望得分 70 分。这也就是我止步于此的地方。接下来,思考我们为什么要枚举 i,目的就是去计算 depiwi。但是,注意到我们不枚举 i 也一样可以计算贡献。我们只需要每次下传的时候加上 p=1nk+1wp 就好了。这样,我们就可以不枚举 i 做到 O(n3) 的复杂度了。接下来,我们可以惊奇地发现,当不枚举 i 的时候,转移的复杂度也自然由 O(n) 变成了 O(1)。因为我们可以每次填一个叶子进来,而不用一次填许多叶子转移了。具体的,我们设 fi,j 表示考虑了 i 个叶子,当前层有 j 个节点。有以下两个转移:将这一层的一个节点钦定为叶子 fi+1,j1=fi,j+lowbit(j1),和下放一层 fi,2j=fi,j+k=1ni+1wk。时间复杂度 O(n2),期望得分 100 分。

D10T3

首先,观察 g 的形式,g(x)={xkxkZg(xxk)xkZ,可以暴力模拟。

g(r,d)=g(rk+d)(0d<(r+1)krk,显然有 g(r,d)=g(r,dmod(r+1)),所以 g(r,) 有长度为 r+1 的循环节。可以在 O(kVk) 的时间复杂度内进行单点求值。

考虑优化单点求值的过程,因为有循环节,所以下面只讨论 0dr 的情况。

rk(r1)k(1)k+1(modr)

g(r,d)={rd=0g(r1,(d1+(1)k+1)modr)1dr

g(r,d)={rd=0g(r1,dmodr)2k,1drg(r1,r1)2k,d=1g(r1,d2)2k,2dr

g(r,d)={rd=0d12k,1drg(r1,r1)2k,d=1g(rd2,dmod2)2k,2dr

α(x) 表示 x 二进制后导零的个数。

g(r,1)=g(r1,r1)=g(r2,(r+1)mod2)=g(r2α(r),1)=g(r2α(r)+1,0)=r2α(r)+1
g(r,d)={rd=0d12k,1drr2α(r)+12k,d=1g(rd2,dmod2)2k,2dr

可以 O(1) 计算单点值。

下面考虑不是单点值的情况,记 s(r,d)=i=0dg(r,d),s(r)=s(r,(r+1)krk1),ss(r)=i=0rs(r),h0(r)=i=1rg(i,0)=i=1ri,h1(r)=i=1rg(i,1)=i=0r1g(i,i)

h0 可以简单 O(1) 求出,h1 可以枚举后导零个数 O(logV) 求出。拆一下式子,有

h(x)=s(xk,xxkk)ss(xk1)
因为 g 有长度为 r+1 的循环节,所以 s 有长度为 2r+2 的循环节,s(r,d)=g(r,dmod(2r+2)),暴力求出每一个 g 即可。

分析 s(r) 的性质,因为 rk(r1)k(1)k+1(modr),所以 g(r,) 形如若干完整的循环节多一项或少一项。具体的,我们有:

s(r)={g(r,r)2kg(r,0)2k,2rg(r,0)h0(r)2k,2r

s(r)={r+12α(r+1)+12kr2k,2rr[rmod4=1]2k,2r

考虑进一步优化,如果 r<d<2r+2s(r,d)=s(r,dr1)h0(r)。然后考虑 0dr 的情况,根据上面 g(r,d),s(r) 的表达式,有

s(r,d)={h0(r)h0(rd21)h1(r)h1(rd+12)2k,0drr2k,d=0rh0(d1)2k,1dr

ss(r)={h1(r+1)2krh0(r)[1rmod84]2k

然后 s(r,d)ss(r) 都是可以 O(logV) 求的,总时间复杂度 O((k+logV)n),可以通过。

D11T1

首先考虑 k=2 的情况。可以转化为求 max{ai+aji×j},将 i 看作斜率 kj 看作自变量 xai 看作截距 b,那么问题就可以转化为求一堆一次函数求最值。显然可以维护出凸包,双指针扫一遍解决。我因为偷懒使用了李超树,反正可以过。

注意到一个性质,每选一个数,答案最多增长 V,所以乘积也最多增长 V。而每次乘积最少会变成原来的二倍,所以乘积的最大值是不会超过 2V 的。所以至多选择 logV 个不是 1 的元素。下文令 k=min(k,logV+1)。然后就可以设计一个暴力的 dp。设 fi,j 表示选了 i 个数,乘积为 j 的最大和,转移比较显然。直接转移可以通过 Sub4 的数据。

去观察更多的性质,注意到:

有一个可重集合 S,满足 xS0x<23,x=1,那么一定存在一个 S 的子集 T ,满足 12xTx23。证明考虑每次选两个最小的合并。

我们考虑将选择的数分成两半,然后用 k=2 的方法合并。由于有以上引理,所以我们可以知道,至少有一种划分方式,满足每一半的大小都 V23。可以通过类似于狄利克雷卷积的方式,用选 a 个的 dp 值和选 b 个的 dp 值在 V23logV 时间内得到 a+b 的 dp 值。暴力计算出每一个的 dp 值,然后去合并,时间复杂度 O(V23log2V),并不能通过。

还需要观察更多性质,注意到:

有一个可重集合 S,满足 xS,0x<13,x=1,那么一定存在一个 S 的子集 T ,满足 |S|2|T||S|2,12xTx23。证明考虑假设 |S| 是偶数,选出所有排序后位于偶数位置的元素。

如果所有的元素大小都 V13,那么一定存在一个子集 T 满足 |S|2|T||S|2,只需要从 k2k2 合并。如果存在一个元素 >V13,那么剩下元素的乘积一定是 V23 的。所以可以从 1,k1 合并。观察我们上面预处理 dp 值的方式,可以通过快速幂的方式得出来我们所需位置的 dp 值。时间复杂度 O(V23logVlogmin(k,logV)),可以通过。

D11T3

注意到 1990199121(mod20242024),所以只需要考虑 zgcd(u,i)mod2,wimod2 构成的两个 bitset(下面记作 Wi,Zi)即可。

首先考虑 Zi,我们考虑暴搜,每次在 u 上加入一个质因子,维护哪些数的 gcd(i,u) 发生了改变。也就是维护 Zivali=gcd(i,u) 两个数组,然后回溯直接撤销,毛估估一下次数不会很多,事实上只有 $X=43474197$ 次。所以复杂度是对的。

然后考虑 Wi。我们考虑维护出来每次哪些 Wi 发生了变化,然后前缀异或起来就是当前时刻的值。 每次发生变化的 Wi 就是 [l,r] 构成的虚树,也就是这中间每个点到根节点路径的并集除去 lca 到根节点的路径,后者可以用 ST 表来处理出来,下面考虑怎么处理前者。

考虑分块,设块长为 B。如果 l,r 属于不同块,我们可以离线到中间一个分界点上。然后处理以每一个分界点为左端点和右端点的每一个区间虚树的情况,这部分复杂度是均摊 O(n2B) 的。如果属于相同块,暴力处理,由于数据随机,这部分复杂度是 O(nB) 的,视为 n,q 同阶,复杂度为 O(nn)

为了卡空间,我们要离线下来处理 Z,可以省出来一个 n2 级别的 bitset。时间复杂度 O(n2w+nn),可以通过。

D12T1

题意可以转化为将节点按照标号顺时针放到一个圆上,每条边作为连接圆上两点的弦,所有的弦仅在端点出相交。在这个问题中,我们可以断环为链,任意钦定一个点作为起点,然后将答案乘以 n

首先考虑树的情况,我们钦定根节点为圆的起点,观察到,根节点对应的任意两个子树,一定是占据了圆上一段连续的位置,且互不相交。所以当一个节点为根时,他和他的子节点一共有 degu 个,所以就有 degu! 种方案,所以总的方案数就是 ndegi! 种。

发现对于每一个环,环上相邻的节点在圆上也一定相邻,所以每个环只有两种方案,顺时针和逆时针。考虑建出圆方树,类似的,每个圆点可以对与他相邻的方点安排一个相对顺序,所以这一部分的贡献就是 udegu!。总的贡献就是 2cnudegu!,其中 c 表示大小 >2 的点双数量。

这样,我们就解决了保证有解的情况,下面我们要观察哪些情况无解。不难发现,有解的点双必须满足由一个大环和一堆连接环上两个不相邻的点的不相交的弦组成。如果两条弦相交显然不合法。如果环之外还有点那么无论这个点放在哪里都会与其他边相交。所以我们需要的就是判断点双是否满足这样的条件。首先,一个必要条件是这个图是广义串并联图,所以可以通过缩二度点的方式将这个图缩到还剩两个点,如果不能那么答案为零。但是这个条件并不充分,不能判断环之外还有没有点。我们可以在缩二度点的过程中,记录哪些边是大环上的,不难发现,如果我们记录每条被缩的时候仍然没被新再次覆盖的边,那么这些边基本就是大环上的边。唯一的特例就是最后剩下两个点连接他们的那一条边也有可能是大环中的边,特判一下就好了。然后知道了大环上的边之后,就可以判断这些边是否能连成一个大环,具体的说就是去判断是否每个点的度数均为二即可。容易用 set 或 map 维护出这个过程,时间复杂度 O(mlogn)

D12T2

赛时一直以为是巨大的树剖单 log 科技题,被狠狠薄纱了。

考虑点分治,对每个分治中心维护一个桶表示距离分治中心为这个距离的点有多少个。然后再维护两个指针,表示最小值和次小值位置。这样就可以简单地计算这个分治中心对应的最小值和个数,然后在全局再维护一个桶表示答案。修改的时候遍历这个点在点分树上的所有祖先,O(1) 计算出他们之间的距离并在对应的数组上删去,同时维护两个指针的移动。这些都是均摊 O(1) 的。由于如果两个点来自分治中心的同一子树,那么全局答案一定比这个答案小,所以也不用考虑减去这种的贡献。所以总的时间复杂度就是均摊 O(nlogn) 的。

D13T1

感觉是嗯出出来的构造题。

首先发现可以通过 xax+1bx 的方式水步数。每次可以这样走四步,要求 a,b 是没有和 x,x+1 连过边的点。具体来说,令 q 是一个小常数,可以选取 xx+qx+1x+q+2xx+q+4xx+q+6x... 的方式进行这一部分。因为在 xx+1x+1x+2 过程中都与 x+1 相邻,所以我们采取隔一个选一个的方式避免重复。所以这样每次扩展需要 k+q+2 个数,与 x+1 相邻的有两个,他们对应的这些数不能相同,也就是要求 2k+2q+4n,所以只需要取 q=4 即可。

然后考虑 k4 的情况,分类讨论嗯构造即可。

D13T2

首先考虑一条链的情况,转化一下问题,构造一些变量 xi[li,ri],有一些限制,xi=xjmax(xi,xj)lmin(xi,xj)r。这个问题显然可以用 2-SAT 解决,令 fi,j 表示 [xi<j]。那么可以将限制表示为 fi,li=0,fi,ri+1=1fi,k=fj,k 的形式,这些都是可以用 2-SAT 刻画的。

接下来考虑树,树缺乏好的性质,但是同样可以找到一组 01 变量来确定 xi 的值。具体的,我们令每条边的方向为一个 01 变量,去构造一棵内向树,树根就是答案。这样的一组 01 变量与一个 xi 显然一一对应。具体的说,我们需要对于每一个变量 xi 分别构造一棵内向树。考虑如何用 2-SAT 刻画内向树的条件,令 fi,j 表示 i 对应的树,jfaj 的边是否是向上连的。根据经典结论,内向树等价于每个点的出度至多为 1。对于每个点相邻的边至多有一条连出去的。这个条件可以通过前后缀优化建图做到边数 O(nm)。然后考虑限制条件,ai 的范围这个条件相当于钦定了树上一些边的方向。具体的说,如果 (u,v)E,ufV(Ai),vfV(Ai),那么这条边一定是 vu 的。2-SAT 很容易可以做到钦定一条边的方向,这部分的边数也是 O(nm) 的。然后考虑第二个条件,如果边 (u,v)V 的虚树上,那么对于任意 i,jSfi,u=fj,u。如果暴力连边的复杂度是 O(n|S|) 的,不能通过。

考虑优化这个东西,我们发现,每个限制其实是对 Vi 的虚树上的所有边,他们对应 Si 中元素的值全部变相同,这个东西看起来就很能用并查集刻画。可以用并查集来合并变量,然后建边。但是由于每次有 n|S| 个变量,所以复杂度仍然是 O(n|S|) 的。 发现整个虚树上合并的都是一样的 Si,所以可以考虑用树剖来维护。树剖,线段树每个节点维护在这个节点所代表的区间的任意节点都存在的合并操作。显然往线段树上加边的复杂度是 O(|V||S|log2n) 的,因为远远跑不满所以可以通过。最后用类似于线段树分治的思路,可撤销并查集维护每个点处 m 个变量的合并关系,显然复杂度不会超过 O(|V||S|log2n+nmlogn),这个上界是极其宽松的,可以通过(甚至比 O(nmlogn+|V||S|) 的点分治快)。实际上需要注意常数的部分反而是 O(nm) 的前后缀优化建图,注意点数和边数上所带的常数不能太大。

D14T1

赛时胡了一个感觉很正确的 LCT 做法,但是由于不会 LCT 就摆烂了。

官解并没有使用 LCT。首先考虑暴力怎么做,边权从大到小枚举每条边,check 这条边是否能被删去。设 G 为删去 s 和与之相邻的边的图,那么充要条件就是联通块个数 k,且 s 与每个联通块都有至少一条边,与 s 相连的边数量 k。暴力 check 时间复杂度 O(m2)

优化这一过程,考虑进行线段树分治。将对 0m 建立线段树,初始时每个节点表示只考虑 i+1m 的边的情况。然后从小到大扫一遍,用可撤销并查集维护上面的三个条件,都是容易维护的。当递归到叶子节点时,判断当前节点对应的边是否必须加入。如果不必须加入就不用管了。如果必须加入发现以后都可以选择这条边了,所以只需要把这条边加入到线段树 i+1m 的区间就可以了。时间复杂度 O(mlogmlogn)

D14T2

首先考虑一个区间 [l,r] 会被分裂成的区间由它出现后的分裂操作决定。不难发现,区间 [l,r] 会被变为 [x,y] 当且仅当 [x,y] 是两个相邻的分裂点或 l,r。如果 [l,r] 被分裂为 [x,y],那么 [l+1,x] 的有效分裂一定选择右边,[y,r1] 的有效分裂一定选择左边。而有效的分裂一定是在它之前没有出现过已经把它干掉了的分裂。也就是说,有效分裂是 [l+1,x] 的所有前缀最小值和 [y,r1] 的所有前缀最小值。用单调栈维护可以做到单次 O(n)。总时间复杂度 O(n2)

考虑特殊性质的做法,特殊性质满足了每个区间任意时刻的状态只有以下几种情况:没被分裂过;是某个分裂点左侧或右侧的一段,是两个相邻分裂点之间的一段。考虑按顺序处理分裂操作并维护区间的形态,我们维护两棵线段树 tr0,tr1i 个位置分别表示由 i 向其右边的第一个分裂点的区间个数期望,由 i 向其左边的第一个分裂点的区间个数期望。左右两边都是分裂点的区间在 tr0 上维护。但是这样没法维护每个区间初始的状态,可以预处理出来每个区间第一次被分裂是被哪一个分裂点分裂,然后在那个分裂点的时候加入那个区间。每加入一个分裂点 x,令它左右两边的第一个分裂点(假设都存在)为 l,r。我们需要将 tr0[l,x1] 的区间取出来,其中以 12 的概率右端点变为 x,左端点不变,这一部分就是线段树区间乘 12,还有 12 的概率变成以 x 为左端点,r 为右端点,求区间和之后加在 tr0x 节点上即可。对 tr1 的处理类似。然后加入在这个分裂点第一次加入的区间即可。时间复杂度 O(mlogn)

对于没有特殊性质的情况,对序列分块,每 B 个操作一块。对于第 i 块的加入操作,第 i+1mB 的块中的分裂操作对它是满足特殊性质的。所以我们对每个块内的加入操作用暴力的做法处理出它在块尾的时候有可能被分裂成哪些区间,概率是多少。然后对这些区间用特殊性质的做法,找到所属的第一个分裂点,然后每次用线段树维护。分析一下复杂度。对于第一部分的处理,复杂度为 m2B2B=m2B。然后每一块被分裂出 m2B2 个区间,每次加入一个区间需要 logn 的复杂度,这一部分是 m2Blogn 的。然后每一块有 m 个分裂操作,分裂操作的复杂度就是 O(mBlogn),预处理的复杂度也是 O(mBlogn)。取 B=m 时取到最小值 O(mmlogn)。实际要把 B 取大一点,因为区间个数是跑不满的。

D15T1

首先考虑一个简单的贪心,我们令左括号为 1,右括号为 1。我们关注前缀和最小值位置 pos。显然 pos 以前需要将一些右括号换成左括号,以后需要将一些左括号换成右括号,这两边是类似的,下面我们只考虑左边的情况。我们扫一遍,用一个堆维护可以由右括号变成左括号的权值。每次直到不得不换一个的时候,从堆里取出最小值加进答案。两边的答案拼起来恰好就是最终答案,时间复杂度 O(nqlogn)

考虑用数据结构优化上面的贪心过程。我们令上面需要取出堆顶元素的点称为关键点。那么每个关键点匹配一个它之前的未被匹配的 ai。将询问离线,用线段树分治变成只加的问题。我们发现无法维护每个关键点选的 ai,考虑维护没选和选了的关键点集合,以及被匹配的 ai 集合和未被匹配的 ai 集合。考虑新加入一个点带来的影响,首先线段树二分找到第一个 x 之后没被选的关键点。如果存在,直接令 x 匹配它,在线段树上做对应修改。否则 ax 最多替换掉一个已经被匹配的 ai。考察哪些能够被 ax 替换。我们在线段树上再维护一个变量表示选了的关键节点取出后对应的堆大小。我们线段树二分找到 x 的关键点中最大的一个大根堆为空的位置,记为 p。这种位置显然它前面的 ai 匹配的都是它和它以前的关键点,所以这些关键点是不能被 ai 替换的,而其他的关键点可以通过调整匹配方式来使得任意一个 ai 能被 ax 替换。所以我们在线段树上查找 [p+1,pos] 这一段选进去的匹配点最大值,判断它是否能被替换掉,并在线段树上维护对应的修改操作。时间复杂度 O((n+q)lognlogq),不能通过。

其实可以不用线段树分治。我们可以类似加入操作用线段树维护删除操作。具体的,我们先去判断它是否匹配了关键点。如果未匹配,我们只需要在未被匹配的 ai 集合中将它删去即可。否则我们找到第一个 x 的堆为空的位置,记为 p。类似的可以说明,我们如果删去 x 一定要在 p 的范围内选进去一个。如果发现 p 没有未被选的节点,那么我们将最后一个关键点变为空关键点,同时维护其他元素的修改操作。否则我们找到 p 的范围内没选的最小元素,把它选进去,同样用线段树维护所有相关的修改。时间复杂度 O((n+q)logn),细节很多。

D16T1

首先对于 ai11 的部分分,首先发现答案的上界是 S=ai10 是答案上界。考虑贪心,能填 11 就填 11,否则随便填,如果最后剩的是 11,一定每次都进了位,所以不难发现答案的另一个上界是 n,并且一定能取到一个上界。所以答案就是 min(S,n)。直接 dp,用前缀和优化容易做到 O(n2)

考虑 ai12 的情况,我们无法保证每一个当最后剩下 12 时每一个数都能贡献有效进位,例如 {1,12,12,12,12,12},考虑每个 1 何时能在这种情况下带来一个有效进位,需要此时选了的和是奇数才能带来进位,所以每个 1 需要找一个其他奇数一起才能独自带来进位,否则只能两两组合带来一个进位。所以贡献就是 min(S,nmax(0,c1(c3+c5+c7+c9+c11))2)。考虑按照 3,5,...,1,2,4,...12 的顺序直接进行暴力 dp,时间复杂度 O(n3),结合上面的能得到 76 分。

上面这个 dp 由于转移形式的特殊性很难进行前缀和优化,考虑用其他方式进行优化。记 f(i,j) 表示 3,5,7,9,11 的 dp 值,g(i,j) 表示 2,4,6,8,10,12 的 dp 值。这两个东西仿照特殊性质用前缀和优化 dp 是可以做到的,这部分时间复杂度 O(n2)。设 h(i,j) 表示 1,3,5,7,9,11 的 dp 值,考虑如何做到 fh 的转移。考虑转移的形式,设 x 表示选择 1 的数量,那么转移形式为 h(i+xmax(0,xi2),j+x)f(i,j)。观察这个形式,发现转移点是类似于 (i,j)(i+1,j+1)...(i+i,j+i),(i+i,j+i+1)(i+i+1,j+i+2),(i+i+1,j+i+3)... 的形式,大概是前面一条斜率为 1 的直线和后面两条斜率是 2 的直线拼起来,所以可以用两个差分数组分别维护斜率为 12 的直线,差分转移即可,时间复杂度为 O(n2)。如果仍按照 3,5,...,1,2,4,...12 的顺序转移,剩下的部分采用前缀和转移拼起来的话,由于毒瘤出题人卡了常数,很难通过。要考虑一个更优的做法。我们已经预处理出了 hg 两个数组,需要对他们进行背包合并。但是这个背包合并是有性质的,考虑如果每一个都按 n 来贡献答案的话,两部分是独立的,容易 O(n2) 做到。但是这样多算了一部分,就是如果选取 S 做贡献的部分。注意到现在答案的差值只和 (j10i,jmod10) 有关,这种二元组个数是 O(n) 的,暴力枚举这种二元组,时间复杂度 O(n2),常数变为大约了 12,可以轻松通过。

D17T1

首先不难想到去构造 1,2,4,8... 的序列,发现每构造一个需要 3 个数,这样大概需要 X=999,Y=333 的样子。考虑采用其他进制,发现可以使得 Y 变小一些,但是 X 仍然很大。所以转而使用打表搜索使用不同进制的时候能做到的 X,Y 和形态。

打表观察到使用 21,34,55... 进制时 X 比较优,发现这些数满足斐波那契数列,向这个方向思考。观察能够发现,如果已经能够凑出 fibi,那么可以通过新增两个格子达到 fibi+1。又可以发现 fib481>10100,所以只需要得到前 480 项,可以用 X=960 做到。又根据经典结论,将一个数用斐波那契数列凑出来一定不会需要相邻两项,所以最多只需要 Y=240 项,也刚好够用,所以就做完了。

D17T2

赛时以为是 D14T2 只能做出性质 B,其实和那个题仅仅是长得比较像而已,做法可以说是毫不相关。

首先考虑性质 AB 的做法,由于性质 A 的存在,每个区间只会变化 log 次。考虑暴力维护这些变化,不难发现就是找到修改时间最早的在这个区间的分裂操作,可以用 ST 表简单维护。如果没有 B 性质,考虑用线段树代替 ST 表来支持修改操作。从 1n 扫描线,每次在线段树上加入和删除一些分裂操作,然后在线段树上查询区间最小值,时间复杂度 O(nlog2m+mlogm)

如果没有 A 性质,虽然可以用 D14T2 的做法来做 B 性质,但是如果没有 B 性质就很难规避树套树或分块了。考虑这个题的操作和那个题的区别,这个题只保留了一个区间。我们考虑没有了 A 性质,就会出现 O(n) 次分裂。考虑为什么会有这么多次分裂,如果我们一直靠边分裂,就会分裂地很缓慢。所以,我们考虑将区间划分成三等分 [l,ml][ml,mr][mr,r]。注意到当出现 [ml,mr] 之间的分裂之前,[l,ml] 的分裂一定保留右边,[mr,r] 的分裂一定保留左边。所以,我们令出现在 [ml,mr] 之间的分裂为关键分裂,那么关键分裂只会出现 O(logm) 次。下面考虑如何模拟这个过程。发现我们的过程是,在关键分裂以前,对于 [l,ml] 中找到最大的位置成为新的左端点,对于 [mr,r] 之间最小的位置成为新的右端点,然后进行关键分裂。所以我们只需要扫描线维护单点修改,对于每一个区间,在线段树上二分找到出现时刻 <t[l,ml] 之间最大的数和 [mr,r] 之间最小的数。然后找到 t 时刻修改在 [ml,mr] 区间的具体位置,手动模拟这一次分裂操作。发现每次进行关键分裂必然会使区间长度变为原来的 23,所以时间复杂度是 O(nlog2m+mlogm) 的。

posted @   Harry27182  阅读(118)  评论(1编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示