SD 三轮省集

Day 1

模拟赛 T1

给你一棵树,每个点维护一个二元组 \((a_i,b_i)\),要求支持两种操作:

  1. 输入 \(x,c\),设当前操作编号为 \(z\),则对 \(x\)\(1\) 路径上的每个点 \(u\),若 \(a_u\neq c\)\((c,z)\to (a_u,b_u)\)
  2. 输入 \(x\),查询 \((a_x,b_x)\)

\(n,q\leq 10^6\)。2s 512MB。

首先注意到信息有结合律,没交换律,也没差分,但是只支持时间区间不交的两个信息合并。树剖可以做 2log,卡卡常能过。上个 LCT 或者 GBST 之类的东西可以优化 1log。

然而有一种小清新做法。考虑离线下来,给每个点开一个时间轴上动态开点线段树,然后可以线段树合并做到 1log。

模拟赛 T2

\(n\times n\) 平面给 \(n\) 个矩形,再给出 \(m\),对于每个 \(1\leq m\times i\leq n\) 求出有多少整点恰好被覆盖 \(m\times i\) 次。

\(n\leq 3\times 10^5,n\leq m^2\leq n^2\)。8s 512MB。

考虑扫描线,这样变成了维护一个数据结构支持区间加,查询有多少数等于 \(x\)。直接分块,设块长为 \(T\),可以得到 \(O(\frac{n^2}{\sqrt m})\)

考虑继续优化。我们记录每个块内的最大最小值,然后查询的时候只对有值的那一部分查。因为只有散块修改会改变极差,所以极差总和是 \(O(n)\) 的。复杂度 \(O(\frac{n^2}{m}+n\sqrt n)\)

模拟赛 T3

\(n\times n\) 平面先 \(n\) 次矩形 chkmax,然后 \(m\) 次询问矩形和。

\(n,m\leq 2\times 10^5\)。12s 512MB。

前置知识:序列线性并查集。

唐,,。

QOJ8704

说人话,相当于维护一棵树,儿子之间有顺序,操作是加叶子,把一棵子树接到一个点的下面,查询一个点祖先左边子树的大小之和。

考虑贡献,若 \(x\) 贡献到 \(y\) 则连边。发现是一张竞赛图,还可以发现贡献具有传递性。所以贡献关系是一个序列 \(p_n\)\(\forall i<j\)\(p_i\) 贡献到 \(p_j\)。相当于每个点的答案等于这个点的排名值,用你喜欢的平衡树维护这个序列就行。

CF1814F

肯定考虑线段树分治。然而还要统计能不能到达 \(1\),不难想到在并查集上打标记,但是这样好撤销吗?发现线段树分治的并查集自然地形成了一个重构树,每次撤销断的边一定是根的一条边,所以可以在断边的时候下传标记。

Day 2

模拟赛 T1

一棵 \(n\) 个点的树,要选出一段编号连续的点,满足 \(m\) 条限制:\((u,k)\)\(u\)\(k\) 级儿子中至少选一个。问最少选多少点。

\(n,m\leq 2\times 10^5\)。1s 512MB。

首先看到这个玩意不难想到 BFS 序变成区间问题,就变成了用编号连续的一段点覆盖每个区间。进一步可以发现区间只有包含关系,而且只有最里面的有用,于是把没用的删了双指针扫就行。

UOJ553

产生贡献当且仅当 \(x^2+(y-z)^2\leq r^2\),进一步化为 \(x^2+y^2+2yz+z^2-r^2\leq 0\),相当于给出点 \((z,z^2-r^2)\) 和直线(一般式)\((2y,1,x^2+y^2)\),问一个点下面有多少直线。

考虑对直线序列分块,设块长为 \(B\)。对每块枚举出这些直线的 \(S^2\) 个交点,按 \(x\) 坐标排序,把所有询问离线,也按 \(x\) 排序。从左往右扫,动态维护一个块内直线从下到上的顺序。扫到一个交点就交换这两条直线的顺序,扫到一个询问就对每个块二分查一下下面有多少直线。\(S\)\(\sqrt n\) 可以得到 \(O(n\sqrt n\log n)\) 的复杂度。

P9996

如果数据不随机考虑套用上一题,对所有点随便分块,把所有询问按斜率排序。对于一个确定的斜率,给每个点标上顺序,这样查询半平面就是查这些点的前缀。斜率变化的时候块内点的顺序一定是相邻交换,查询直接二分即可。

如果保证数据随机,有两种做法。

第一种是直接 KDT。第二种是平面分块。分成 \(\sqrt n\times \sqrt n\) 个块,每块期望 \(O(1)\) 个点,一条直线最多经过 \(O(\sqrt n)\) 个块,散块暴力整块预处理前缀和。都是 \(O(n\sqrt n)\) 的复杂度。

模拟赛 T2 P8261

考虑怎么把 UOJ553 套过来。如果一个颜色的出现次数大于 \(\sqrt n\),那么直接用那题做法套,这一部分总共是 \(O(n\sqrt q\log q)\) 的。对于那些出现次数不足 \(\sqrt n\) 考虑凑起来一块做。把这些颜色挨个加,如果当前总数超过了 \(\sqrt n\) 就做一遍,清空,可以得到每次做一定不超过 \(2\sqrt n\) 所以复杂度是对的。但是不能直接做,还好是邻项交换所以可以直接动态 \(O(1)\) 维护前缀和。复杂度 \(O(n\sqrt q\log q)\)

P5607

首先把 \(|S\cup T|\) 换成 \(|S|+|T|-|S\cap T|\)

肯定对一个集合被插入的次数根号分治,吗?如果这么想就错完了。要对元素被插入的次数根号分治,设阈值为 \(B\)

对于出现大于 \(B\) 次的最多有 \(\frac{m}{B}\) 个,对于这部分,每个集合维护一个长度为 \(\frac{m}{B}\) 的 bitset,查询 \(O(\frac{m}{Bw})\),修改 \(O(1)\)

出现次数小于 \(B\) 的,直接维护所有集合对之间的答案。空间会爆吗?不会。值非零的地方最多 \(mB\) 个,用哈希表存即可。修改直接暴力遍历这个元素出现的所有集合然后修改答案。查询 \(O(1)\),修改 \(O(B)\)。平衡得到总复杂度 \(O(m\sqrt\frac{m}{w})\)。可以通过。

卡常卡了很久,主要是换成了手写哈希表和分讨集合内元素个数来把 bitset 个数除以 \(2\)

Day 3

模拟赛 T2 QOJ5022

考虑贡献矩阵 \(f_{x,y}\) 表示一开始在下标为 \(0\) 处放一个 \(1\),经过 \(x\) 步操作后 \(y\) 的值。观察这个东西的形状,发现是一个分形结构,然后可以发现 \(f_{x,y}=[y\subseteq x]\)。证明考虑网格图路径技术和 Kummer 定理。

对于操作为全局的数据,直接定期重构。重构的时候考虑一个类高维前缀和的东西,可以 \(O(n\log n)\) 重构。

考虑正解。定期重构配合分块。让重构阈值小于块长,这样最多只有相邻两块产生贡献,而且一个块末尾的值只跟块内元素有关。重构的时候,从后往前枚举每个块,每次把这个块和前面相邻的一个块拎出来做全局的做法即可。

模拟赛 T3

首先可以发现操作一定是先加后减。分讨可以证明。

然后可以设 \(f_{i,j}\) 表示让前 \(i\) 个元素符合要求,第 \(i\) 个元素用了 \(j\)\(-1\) 操作。然后发现没法转移,因为若 \(b_i=0\),则没法推断出来减了多少次。那直接把 \(b_i=0\) 的连续段缩成一个点,\(a_i\) 为段内所有 \(a_i\)\(\max\),这样转移的时候最多只会隔着一个 \(b_i=0\) 的,直接跳过这个转移,将其变成限制,相当于至少 \(a_i\)\(-1\)。使用一些手段即可做到 \(O(nV)\)

打个表发现是凸的,而且斜率的种类很少,所以直接维护拐点即可。

Day 4

模拟赛 T1

有一个长为 \(n\) 的数列 \(a\) 和一个长为 \(m\) 的数列 \(b\),保证拼接起来后是 \(n+m\) 的一个排列。接下来会进行若干轮操作,每一轮操作:

  1. 若当前为第奇数轮,删掉 \(a\) 中最大的元素,否则删掉 \(a\) 中最小的元素。
  2. 你从 \(b\) 中选一个元素插入到 \(a\) 中任意一个位置。

问最少多少轮能使 \(a\) 递增,或确定这是无解的。

\(n,m\leq 3\times 10^5\)

首先注意到最后作为结果的 \(a\) 一定保留了最初的 \(a\) 的一个值域连续的段。而且若两个段互相包含,则选大的段一定不劣。所以维护一个双指针,每次先移右端点看看是不是下标连续的,行就移,否则移左端点。现在考虑计算答案。

设当前计算的值域连续段为 \([L,R]\)。则要做的是把值域为 \([1,L-1]\) 以及 \([R+1,n+m]\)\(a\) 删掉,并且不要让新加的 \(b\) 影响到计划。容易发现 \([L,R]\)\(b\) 随便加是不会产生影响的,所以先用这些把两边能删的尽量删了。

然后呢?如果其中的一边删干净了,那么就可以用这一边的 \(b\) 来把另外一边的删干净。那如果两边都没删干净呢?考虑先往一边加 \(b\),把另外一边删干净,再用另外一边的 \(b\) 把这边删干净。不知道选哪边两边都尝试一下就好了。

最后你需要把这一坨模拟每一步分别改成 \(O(1)\) 的,就可以 \(O(n+m)\) 通过此题了。

T3

计划补一下。

Day 5

模拟赛 T1

\(n\) 个节点有根树,有 \(n\) 个人要依次从根节点出发,执行任务。编号为 \(i\) 的人会从根节点出发,到达 \(i\) 节点,然后停留 \(a_i\) 秒,最后消失。人走一条边花费 \(1\) 秒,且同一时刻一个节点上只能存在最多一个人。若根节点有人,则要出发的人会等根节点上的人离开后再到达根节点然后出发。问所有人都完成任务要多长时间。

\(n\leq 3\times 10^5\)

考虑序列问题。不妨画出一个坐标系,可以发现一个人一定是尽量紧贴着前面一个人走的。考虑动态维护一段前缀人的轨迹,维护出每个节点还存在人的最晚时刻,设为 \(f_i\)。若一个人要走到 \(u\),设到当前节点的时间为 \(x\),则对 \(i=1\sim u\) 依次执行 \(x=\max(x,f_i)+1\) 后就是到达 \(u\) 的时间。更新的话,可以用平衡树维护斜率为 \(1\) 的连续段。

序列问题上树直接树剖,注意讨论重链之间的转移。\(O(n\log^2n)\)

模拟赛 T2

题目名:互相抵消。

维护一个 DS 支持区间加,区间 \([L,R]\) 求:

\[\sum_{L\leq l\leq r\leq R}((\sum_{l\leq i\leq r}a_i)^2+(R-L+2)(r-l)a_la_r) \]

\(n,q\leq 5\times 10^5\)1s

一看就是推式子题。考虑每对 \(a_ia_j(i\leq j)\) 的贡献,容易发现原式等于:

\[2\sum_{L\leq i\leq j\leq R}((i-L+1)(R-j+1)+(R-L+2)(j-i))a_ia_j-\sum_{L\leq i\leq R}(i-l+1)(R-i+1)a_i^2 \]

此时直接把贡献拆开,发现只需要维护区间 \(a_ia_j,ia_ia_j+ja_ia_j,ija_ia_j,a_i^2,ia_i^2,i^2a_i^2\) 的和就好了。而前三项可以由 \(a_i,ia_i,i^2a_i\) 这三个好维护的值推出来。于是现在我们会了理论最优解——\(O(n\log n)\)!然而常数太大跑不过去。

注意到题目名为互相抵消,而到现在为止我们抵消了个鸡毛,说明还要继续推式子。

发现要维护那么多值的原因是贡献要保证 \(i\leq j\)。于是直接:

\[\begin{aligned} &\quad2\sum_{L\leq i\leq j\leq R}(i-L+1)(R-j+1)a_ia_j\\ &=\sum_{L\leq i\leq j\leq R}(i-L+1)(R-j+1)a_ia_j+\sum_{L\leq j\leq i\leq R}(j-L+1)(R-i+1)a_ia_j \end{aligned}\]

然后进行一些合并,可以发现原式等于:

\[[\sum_{L\leq i\leq R}(i-L+1)a_i][\sum_{L\leq i\leq R}(R-i+1)a_i] \]

于是只需要维护 \(a_i,ia_i\)

Day 6

模拟赛 T1

给定 \(|\Sigma|,n,k\),问多少字符集大小为 \(|\Sigma|\),长度为 \(n\) 的字符串不含有长度为 \(k\) 的回文子串。模 \(10^9+7\)

\(n\leq 10^3,k\leq 25,|\Sigma|<10^9+7\)

套路了。仿照一轮省集 D7T2 搞出每个 border 等价类来。然后考虑容斥,钦定长度为 \(k\) 的回文串出现了 \(x\) 次,则系数为 \((-1)^x\)。把容斥系数带进去 DP 就行了。

模拟赛 T2

对于一个长度为 \(n\) 的序列 \(a\),定义其价值为其所有子序列的异或和。

给定 \(n,m,x\),求最小的 \(k\) 使得长度为 \(n\) 且价值为 \(k\) 的序列 \(a\) 的方案数 \(\bmod m=x\)

\(T\leq 100,n\leq 10^{10000},0\leq x<m<10^9\)

首先经典结论,设 \(a\)\(\operatorname{or}\) 和为 \(A\),则价值为 \(A\times 2^{n-1}\),方案数为 \((2^n-1)^{\operatorname{popcnt}(A)}\)

则我们只要求出 \((2^n-1)^t\equiv x\pmod m\)\(t\) 的最小值,那么 \(A\) 直接取 \(2^t-1\)\(k\) 就是 \((2^t-1)2^{n-1}\)

直接 exBSGS 计算即可。

模拟赛 T3

分糖果上树,直接搞即可 \(O(n\log^2n)\)

Day 7

模拟赛 T1

\(n\) 个从左往右依次排列的杯子,第 \(i\) 个杯子容量为 \(a_i\)。开始时第一个杯子是满的。从左到右对每个杯子依次操作,随机选择剩余的 \(n-1\) 个杯子,并将水倒入选中的杯子直到杯子为空或者选中的杯子满了。求结束时每个杯子的期望的水量。\(n\leq 10^5\)

首先注意到只有最后一次有效倒水是往左边倒的,其他情况都是往右边倒。这样一个杯子里的水有两部分,一个是从左边倒过来,一个是从右边倒过来,这两种情况都只会发生一次。而且从右边倒过来的情况,设这个杯子为 \(x\),右边那个杯子里的水量为 \(y\),则倒过来的水量为 \(\min\{a_x,y\}\)。原因显然。

\(f_{i,j}\) 为倒到第 \(i\) 个杯子,水量为 \(j\) 的概率。转移,对于 \(j<a_i\)

\[f_{i,j}=\sum_{k<i}\frac{f_{k,j}}{n-1} \]

特别的对于 \(j=a_i\)

\[f_{i,a_i}=\sum_{k<i,x\geq a_i}\frac{f_{k,x}}{n-1} \]

可以前缀和优化 \(O(n^2)\) 做这个 DP。线段树可以做到 \(O(n\log n)\)

考虑怎么统计答案。可以把对于一个水杯的答案贡献拆成三部分:从左边倒过来的,倒出去的,从右边倒回来的。在线段树上维护一下即可。

模拟赛 T2

给定 \(n,m\) 的唯一分解形式:\(n=\prod_i p_i^{x_i},m=\prod_i p_i^{y_i}\)。求有多少个 \(S\) 满足:

  1. \(|S|=n,1\in S,S\subseteq [nm]\)
  2. \(\exist T,|T|=m,\{i+j|i\in S,j\in T\}=[nm]\)

\(\sum_i x_i,\sum_i y_i\leq 2\times 10^5\)

暴力。考虑怎么判定,可以把这个问题看成一个长为 \(nm\) 的纸带,对于 \(T\) 中的每个元素 \(x\),将 \(S\) 偏移 \(x\) 格后覆盖上,看最后能不能覆盖满。直接设 \(f_{n,m}\) 为答案,考虑转移。可以把 \(S\) 复制任意段拼接在后面,也可以增加覆盖的次数,对应两种转移:

\[\begin{cases} f_{n,m}\to f_{kn,m}\\ f_{n,m}\to f_{n,km}\\ f_{n,1}=1 \end{cases}\]

然而这样会算重,原因是如果一个串复制 \(x\) 次后不能接着复制 \(y\) 次,否则会对 \(xy\) 造成多次贡献。也就是说两种转移只能依次进行,解决方法也很简单:

\[\begin{cases} f_{n,m}\to g_{kn,m}\\ g_{n,m}\to f_{n,km}\\ g_{n,1}=1 \end{cases}\]

答案即为 \(f_{n,m}+g_{n,m}\)

考虑优化。抽象出来这个模型,放到网格图上。一个点 \((x,y)\) 交替进行往下走到 \((kx,y)\) 和往右走到 \((x,ky)\),答案即为所有 \((x,1)\) 走到 \((n,m)\) 的方案数之和。可以发现两维是独立的,设 \(f_i\) 表示 \(i\) 步从 \((1,1)\) 走到 \((1,m)\) 的方案数,\(g_i\) 表示 \(i\) 步从所有 \((x,1)\) 走到 \((n,1)\) 的方案数之和,则答案可由这两个量简单计算。

先考虑 \(f_i\) 怎么算,把这个问题抽象一下,把每个质因子当成小球,走的 \(i\) 步相当于 \(i\) 个盒子,也就是说要把这几种小球放到 \(i\) 个盒子里,要求每个盒子非空。直接钦定 \(k\) 个盒子为空,然后对每个 \(k\)\(dp_i\) 表示考虑前 \(i\) 种质因子的方案数,直接 DP 即可。设 \(S=\sum_i x_i+\sum_i y_i\),复杂度 \(O(S^2)\)

考虑继续优化,瓶颈在于两个地方,一个是 DP,一个是由 DP 值反演出非空方案数。前者注意到次数相同的质因子本质相同,所以本质不同的只有根号个。后者经典用卷积优化。所以最终复杂度 \(O(S\sqrt S)\)

Day 8

模拟赛 T1 P12558

一眼望上去非常像 ABC134F,所以可以一眼秒掉 \(O(n^3)\)。但是往下这么做就倒闭了啊。

考虑怎么判定一个子集能不能满足子集内的恰好打过,自己外的恰好打不过。可以对两个序列排序,让子集内的按顺序小的跟小的打,子集外的大的跟大的打,这样一定更容易满足。

所以可以枚举 \(x\) 个恰好打过,再设 \(dp_{i,j}\) 表示前 \(i\) 个打过了 \(j\) 个的方案数,容易转移。\(O(n^3)\)

考虑优化。发动你的注意力,注意到若枚举了 \(x\) 恰好能打过,则大于 \(b_x\)\(a\) 只要想打一定能打过,小于 \(b_x\)\(a\) 只要不想打一定打不过。换句话说对于小于 \(b_x\) 的前缀,只要确定了哪些能打过,则剩下那些可以安排到一定打不过;大于 \(b_x\) 同理。

于是可以设 \(f_{i,j}\) 表示前 \(i\) 个人有 \(j\) 个打过的方案数,\(g_{i,j}\) 表示后 \(i\) 个人有 \(j\) 个打不过的方案数,可以 \(O(n^2)\) 的时间内算出这两个 DP。然后枚举 \(x\) 合并两个 DP 即可。\(O(n^2+q)\)

posted @ 2025-11-30 11:08  Linge_Zzzz  阅读(0)  评论(0)    收藏  举报