2023 省选做题记录 5.0

目录

女生节就要开新坑(确信)。

3.7

2023.3.7 考试 T2 传奇特级法术树(tree) / [洛谷 P7880] [Ynoi2006] rldcot(dsu on tree + set + 扫描线)

题面

\(n\) 年没做过 dsu on tree 的题了,联考看见这题直接想莫队,被大仙嘲讽了/kk

对于树上统计点对问题考虑 dsu on tree。一个经典套路是枚举 LCA,所以我们可以分别处理每个 LCA 的贡献。

对于每个点 \(u\),考虑维护一些区间 \([l,r]\) 表示如果询问区间包含 \([l,r]\) 就说明这个点可以产生贡献。显然对于 \(u\) 的某个子树内的点 \(v\),假设另一个点 \(w\)(不妨假设 \(v<w\))在 \(u\) 的另一个子树中,那么 \([v,w]\) 就是一个合法区间。注意到如果某个区间包含了另一个区间,那么它可以直接被删去,因为它显然不优。所以说只需要找到和每个点 \(v\) 不在同一个子树的前驱后继,这个可以用 set 快速求出。

前半部分大体就是一个 dsu on tree,它保证了所有区间的数量是 \(\mathcal{O}(n\log n)\) 的。时间复杂度 \(\mathcal{O}(n\log^2 n)\)

对于深度相同的点,考虑将它们放在一起处理。先去掉包含的区间,这个可以将区间按照右端点从小到大排序来处理。扫描线,将区间和查询都在右端点处考虑。假设之前的区间左端点最大值为 \(cur\),现在的区间左端点为 \(l\),那么就将区间 \((cur,l]\) 的答案 \(+1\)。这个可以树状数组维护。

所以总时间复杂度就是 \(\mathcal{O}(n\log^2 n+m\log n)\)

代码:https://paste.ubuntu.com/p/9vnHtTZxPz/

启发:树上点对统计问题要考虑到 dsu on tree。

后面发现可以不用 dsu on tree,直接 set 启发式合并就行/qd。所以场上最后还是有概率冲出来的,恼/fn。

参考沙皇代码:https://paste.ubuntu.com/p/7HZ8fD8kVg/

2023.3.7 考试 T1 传奇特级超空间(dimension)(Lucas 定理 + 递归)

题意:

记在 \(m\) 维超空间中放置 \(n\)\(m − 1\) 维超平面,最多可以将该空间分割成 \(f(n, m)\) 个区域。

例如 \(f (3, 1) = 4\)\(f (5, 2) = 16\)

\(\sum\limits_{i=0}^n f(i,m)\) 对一个给定质数 \(p\) 取模。

数据范围:\(1\le n,m\le 10^{18},p\le 2\times 10^7\)\(p\) 是质数。

递推式:\(f(i,j)=f(i-1,j-1)+f(i-1,j)\)。边界 \(f(i,0)=f(0,i)=1\)

可以理解为:最后一个加入会形成 \(n-1\)\(m-1\) 维的超空间。

考场上一直在对 \(f\) 函数推式子,推得很奇怪,然后直接自闭了。

实际上要考虑对要求的那个 \(f\) 的列前缀和打表,打出来可以发现是一个组合数前缀和。即:答案为 \(\sum\limits_{i=0}^n\sum\limits_{j=0}^m\binom{i}{j}\)。交换求和顺序后用上指标求和可以推导出答案为 \((\sum\limits_{j=0}^{m+1}\binom{n+1}{j})-1\)

进一步推式子:

\[\sum\limits_{i=0}^m\binom{n}{i}=\sum\limits_{i=0}^m\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\times\binom{n\bmod p}{m\bmod p} \]

考虑枚举余数:

\[\sum\limits_{i=0}^{p-1}\binom{n\bmod p}{i}\times\sum\limits_{j=0}^{\lfloor\frac{m}{p}\rfloor-1}\binom{\lfloor\frac{n}{p}\rfloor}{j}+\sum\limits_{i=0}^{m\bmod p}\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\times\binom{n\bmod p}{i} \]

设所求为 \(g(n,m)\),那么上式可以写成:

\[g(n,m)=g(\lfloor\frac{n}{p}\rfloor,\lfloor\frac{m}{p}\rfloor-1)\times2^{n\bmod p}+\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\sum\limits_{i=0}^{m\bmod p}\binom{n\bmod p}{i} \]

直接递归计算即可。

时间复杂度 \(\mathcal{O}(p\log_p\max(n,m))\)

代码:https://paste.ubuntu.com/p/mtK79ZHftj/

2023.3.7 考试 T3 传奇特级字符串(lgs) / [QOJ5256] [CERC2022] H. Insertions(KMP + 失配树 + 二维数点)

题面

题意:

给定字符串 \(S,T,P\),求将 \(T\) 插入进 \(S\) 之后 \(P\) 最多的出现次数。输出:

  • 最多的出现次数;
  • 达到这个最多出现次数的插入位置数量;
  • 达到这个最多出现次数的最靠前的插入位置;
  • 达到这个最多出现次数的最靠后的插入位置。

数据范围:\(1\le |S|,|T|,|P|\le 10^5\)

题目要我们求的信息量很大,不妨直接求出在每个位置插入 \(T\) 之后 \(P\) 的出现次数。

设将 \(T\) 插入之后 \(S\) 前后两部分为 \(A,B\)

讨论 \(P\) 出现的位置情况:

  • 完全包含于 \(T/A/B\):可以直接 KMP 预处理。
  • \(A+T\):求出所有长度 \(x\) 满足 \(T\) 长度为 \(x\) 的前缀和 \(P\) 长度为 \(x\) 的后缀匹配。建出 \(S\) 匹配 \(P\) 的失配树,把所有编号为 \(x-1\) 的节点打上标记,在 \(i\) 后插入 \(T\) 得到的形如 \(A+T\) 的匹配数量就相当于失配树上 \(S_{1,i}\) 匹配 \(P\) 的最长前缀的所有祖先的标记和。
  • \(T+B\):将 \(S\)\(T\)\(P\) 全部翻转,再做一遍 \(A+T\) 的过程。
  • \(A+T+B\):求出所有 \(T\)\(P\) 中的匹配位置 \([x+1,x+|T|]\),然后就相当于统计有多少位置 \(i\) 满足 \(S_{i-x+1,i}=P_{1,x}\)\(S_{i+1,i+|P|-|T|}=P_{x+|T|+1,|P|}\)。求出 \(S_{1,i}\) 匹配 \(P\) 的最长前缀长度和 \(S_{i+1,|S|}\) 匹配 \(P\) 的反串的最长匹配长度,设为 \(u,v\),那么就是问有多少个 \(x\) 满足 \(x\) 在正串失配树上是 \(u\) 的祖先且 \(|P|-x-|T|\) 在反串失配树上是 \(v\) 的祖先。这是一个二维数点问题,可以离线扫描线 + 树状数组完成。

注意树状数组上界要开到 \(|P|+1\)……因为节点数是最大编号 \(+1\)……

代码:https://paste.ubuntu.com/p/xnd9gHx5WD/

3.8

[ABC277F] Sorting a Matrix(性质 + 拓扑排序)

题面

容易发现这个 0 没有任何用,因为如果非 0 的位置满足条件那么一定存在一种填 0 的方案使得最终状态合法。

关键性质:行和列可以分开考虑。

这是因为无论怎么操作,每个数和其所在的行 / 列的数的集合都是不变的。

先考虑行操作。将每一行非 0 位置的最小值和最大值找出来,设为 \(mn,mx\),那么如果所有区间 \([mn,mx]\) 不交就说明可以通过若干行交换操作使得行之间满足条件。

接下来考虑列操作。我们可以用一张有向图来表示列与列之间的大小关系。

对于每一行,如果 \(a_{i,j_1}\le a_{i,j_2}\) 就连边 \(j_1\to j_2\)

只需要判断原图是不是一个 DAG 即可。

但是这样时间复杂度是 \(\mathcal{O}(HW^2)\) 的。

考虑优化连边。

你想要把 \(N\) 个点和 \(M\) 个点一一连边。若连 \(NM\) 条边,边数会太大。因此,我们可以增加一个点 \(u\),把那 \(N\) 个点和 \(u\) 连接,再把 \(u\) 和那 \(M\) 个点连接。

在这个题中,我们也可以这样操作,把一行中同样值的点视为一个点。这样,就只会有 \(HW\) 条边。

代码:https://paste.ubuntu.com/p/9dpQpwBCDT/

[SNOI2019] 通信(费用流 + 分治优化建图)

题面

似乎是典题?

暴力费用流建图显然:\((S,i,1,0)\)\((i,T,1,w)\)\((i,j+n,1,|a_i-a_j|)(j<i)\)\((i+n,T,1,0)\)

直接建图边数有点多,考虑优化,减少边数。

注意到所有形如 \((i,j+n,1,|a_i-a_j|)\) 的连边都是从编号大的连向编号小的,所以考虑分治。

将当前区间所有点的权值拿出来,连成一条链,相邻之间连流量为 \(\infty\)、费用为权值差的边。所有在中点右侧的点向它的权值对应的点连边,在中点左侧的点由它的权值对应的点向它连边。

代码:https://paste.ubuntu.com/p/WkP5bgbz6d/

[ARC120E] 1D Party(二分 + DP)

题面

口胡的。

二分答案 \(k\)。显然除了两端点的人之外每个人都只有两种选择:先左后右 / 先右后左。

考虑把这个设进 DP 状态:设 \(f_{i,0/1}\) 表示第 \(i\) 个人先左后右 / 先右后左能到达的距离它最远的距离。

转移枚举相邻两个人的状态就是了。

具体见洛谷题解。

启发:每个点状态只有有限个时考虑将这些状态设进 DP 里。

2023.3.8 考试 T1 跳蚤的签到(binary) / [清华集训 2017] 小 Y 和二叉树(贪心 + DP)

题面

关键性质:任何一个度数 \(<3\) 的点都可以作为中序遍历的第一个点。

证明:显然。只要让它没有左子树且从根可以一直走左儿子走到它就行了。

设这个点为 \(rt\)。把它当作根,树形 DP 出以每个点为根编号最小且度数小于 \(3\) 的点,设为 \(dp_i\)

\(rt\) 一直找祖先。当它度数为 \(1\) 时显然可以直接终止;度数为 \(2\) 时看它是作为右子树还是父亲节点更优;度数为 \(3\) 时讨论哪个节点作为右子树更优。

具体实现见代码。

代码:https://paste.ubuntu.com/p/J9NGjZ5b2g/

2023.3.8 考试 T2 青蛙的树(tree) / [PA 2017] Banany(点分树 + 线段树 + 卡空间)

题面

考虑单次询问怎么做。考虑点分治,对于每个分治重心 \(rt\) 维护最小的 \(z_u-dis_{u,rt}\),询问的时候直接求 \(\min(dis_{q,rt}+z_u-dis_{u,rt})\) 即可。

多次询问考虑建出点分树,对于每个分治重心开一棵线段树维护 \(z_u-dis_{u,rt}\),修改和查询都直接爆跳点分树祖先。具体的,单点修改直接做,边的修改考虑线段树上权值会改变的位置 dfs 序是一段区间,所以考虑把 dfs 序作为线段树的下标。

但是直接这样做会被卡空间。需要一定的卡空间技巧:

  • 直接对于每一层开一棵线段树,因为同一层的分治中心控制的连通分量点集是不交的,所以可以将这些信息合并到一棵线段树上。
  • 空间消耗:vector < unordered_map < map < gp_hash_table
  • 能不开 long long 就不开,尽量用 int

代码:https://paste.ubuntu.com/p/YBsTMXZ897/

3.9

2023.3.9 考试 T3 Contest(c)(扫描线 + 线段树)

题意:

\(n\) 颗小行星排成一排,相邻两颗小行星距离为 \(1\)。第 \(i\) 颗小行星有一个亮度值 \(x_i\) 和区分值 \(l_i,r_i(l_i\le r_i)\)。对于小行星 \(i,j(i<j)\),我们能区分出 \(i,j\) 当且仅当两者的距离 \(j-i\in[l_i,r_i]\cap[l_j,r_j]\)。两颗可区分的小行星的亮度差为 \(|x_i-x_j|\)

现在苍会不断进行摄像来考察这些小行星。具体而言,每次摄像,会包含一段区间的小行星。你需要回答,在这一段区间中,任意一对可区分的小行星的最大亮度差。如果不存在一对可区分的小行星,报告无解。

数据范围:\(2\le n,m\le 2\times 10^5,1\le l_i\le r_i\le n,1\le x_i\le 10^9\)

考虑从左往右扫描线。建立一棵线段树维护当前会产生贡献的点的亮度值区间 \(\max/\min\) 以及左端点在当前区间内时的答案。

每个点 \(i\)\(i+l_i\) 处加入线段树,在 \(i+r_i+1\) 处在线段树中删去贡献。

更新答案直接用 区间 \(\max/\min\) 减去当前点的亮度值 的绝对值更新,维护两个懒标记分别表示当前区间可以被更新答案的值的 \(\max/\min\)。表述可能不是很清楚,可以见官方题解。

代码:https://paste.ubuntu.com/p/X7SGS2QfnT/

2023.3.9 考试 T1 AtCoder(a)(构造 + 扩展欧拉定理)

题意:

给定正整数 \(a,m\),找到一个 \(x\) 满足 \(x\equiv a^x\pmod m\),且 \(1\le x\le 9\times 10^{18}\)

数据范围:数据组数 \(1\le T\le 10^3\)\(2\le a,m\le 10^9\)

构造 \(x\equiv a^{a^{...}}\pmod {m\varphi(m)}\) 即可。

代码:https://paste.ubuntu.com/p/dyZf4xfpCw/

Codeforces Round 857 (Div. 1) A~D

3.10

2023.3.10 考试 T1 扑克(poker)(爬山 / 二分图匹配 / 欧拉回路)

题意:

你有一套扑克牌,这套扑克牌有 \(n\) 种不同的面值和 \(4\) 种花色。一共 \(4n\) 张牌,每种花色和面值组成的有序对恰好对应着一张牌。现在这 \(4n\) 张牌在桌上被打乱并排成了一列,有些牌正面朝上,有些牌正面朝下。

由于你喜欢不同的面值,所以你想翻转桌上的某些牌使得每种面值的牌至少有一张是正面朝上的。然而你不想亲自动手,所以你让机器人帮助你完成这个任务。

你每次可以选一个 \([1, n]\) 之间的整数 \(x\),然后指挥机器人翻转桌面上的连续四张牌:从左往右数的第 \(4x − 3, 4x − 2, 4x − 1\)\(4x\) 张。

请构造一种操作方式达成你的目标。

数据范围:\(n\le 2\times 10^5\)

爬山,每次随机一个 \(x\) 翻转,如果正面朝上的花色数量变多就进行操作,否则不操作。

正解:考虑建一张二分图,左部点是所有 \(x\),右部点是所有花色。每个 \(x\) 向它区间内有的花色连边,跑二分图匹配。由霍尔定理可知一定有完美匹配。因为每个点度数都为 \(4\) 所以也可以跑欧拉回路。

爬山代码:https://paste.ubuntu.com/p/yzPZcjTMDn/

[ABC256Ex] I like Query Problem(势能线段树)

题面

考虑什么时候操作 1 可以变为区间加,即区间内最大值和最小值相等的时候。根据势能线段树那套理论(Segment Tree Beats),时间复杂度 \(\mathcal{O}(n\log^2 n)\)

代码:https://paste.ubuntu.com/p/8dDRzT7YT7/

[CF1801F] Another n-dimensional chocolate bar(数论分块 + DP)

题面

\(f_i\) 表示剩余还需要的 \(\prod b_j\ge \lfloor\frac{k-1}{i}\rfloor\) 时的最大答案。

容易发现本质不同的 \(i\) 只有 \(\sqrt k\) 个,可以数论分块求出所有取值。

同样的,可以用数论分块预处理出所有可能的状态之间的转移。

具体可见代码。

代码:https://paste.ubuntu.com/p/zdHrJ9pWTq/

[CF1801G] A task for substrings(AC 自动机 + 二维数点)

题面

和 2023.3.7 考试 T3 传奇特级字符串(lgs) / [QOJ5256] [CERC2022] H. Insertions 一样的套路。那个题甚至是加强版。

考虑将询问差分下来,即求出前缀 \([1,r]\) 的答案减去前缀 \([1,l-1]\) 的答案再减去跨过左端点的答案。

对于前缀的情况,建出 \(s_i\) 的 AC 自动机,把 \(t\) 拉上去跑,每走一步就记录 fail 树上终止节点祖先的个数。

对于跨越的情况,再建立所有 \(s_i\) 反串的 ACAM,对于每个询问,记录 \([1,i−1]\) 在正 ACAM 上的节点和 \([l,r]\) 在反 ACAM 上的节点,后者需要先处理后缀的节点然后倍增跳祖先(即在 fail 树上跳到一个 ACAM 的根到该节点的路径上点数 \(\le r-l+1\) 的祖先)。问题转化成:两个节点在对应 ACAM 的 fail 树上的祖先中,有多少对能拼成一个完整的 \(s_i\)

将询问挂在反 ACAM 的对应节点上。处理询问时在反 ACAM 的 fail 树上 dfs,每次进入子树时,将可以和根节点合并成一个 \(s_i\) 的对应节点加上去,可以证明这样的操作是 \(\mathcal{O}(S)\) 的。子树加单点查询,树状数组维护即可。

代码:https://paste.ubuntu.com/p/rNx2SHjMrC/

2023.3.10 考试 T2 翻转(tournament) / [QOJ5407] 北大集训 2020 Day 2(CTT 2020 Day 2)T3 基础图论练习题(竞赛图 + 性质)

题面

竞赛图的性质:

  • 缩点后是一条链。其中每个点都会向拓扑序比它大的点连边。
  • 将所有点的出度从小到大排序,那么每一个 SCC 都是一段区间,且这些区间不交,它们的并是全集。
  • 竞赛图没有自环,没有二元环;若竞赛图存在环,则一定存在三元环。(如果存在一个环大于三元,那么一定存在另一个三元的小环。)
  • 任意竞赛图都有哈密顿路径(经过每个点一次的路径,不要求回到出发点)。
  • 图存在哈密顿回路的充要条件是强联通。
  • 哈密顿问题中,对于 \(n\) 阶竞赛图,当 \(n\) 大于等于 \(2\) 时一定存在哈密顿通路。

兰道定理:

  • 定义一个竞赛图的比分序列为 把竞赛图的每一个点的出度从小到大排列得到的序列。
  • 一个长度为 \(n\) 的序列 \(s\)\(s_1\le s_2\le \dots\le s_n\)\(n\ge 1\))是合法的比分序列当且仅当:\(\forall 1\le k\le n,\sum\limits_{i=1}^k s_i\ge\binom{k}{2}\),且 \(k=n\) 时该式子必须取等。

对于每一个 \(\sum\limits_{i=1}^k s_i=\binom{k}{2}\) 的前缀 \(1\sim k\),它一定是由若干个完整的强连通分量组成的。

我们可以找到所有这样的 \(k\),然后观察一条边翻转对 \(s\) 的影响,手玩即可发现一定是某段区间 \(+1/-1\)。贡献差可以直接预处理,具体见代码。

代码:https://paste.ubuntu.com/p/PsdP2xVZbr/

3.11

2023.3.11 考试 T1 小 I 加好友(friend)(DP + 组合计数 + 容斥)

题意:

一个 \(n\) 人社交网络是每条边存在概率为 \(p\) 的无向随机图。小 I 是其中的一个节点,每当小 I 和一个人有至少 \(k\) 个共同好友,小 I 即与这个人成为好友。

求小 I 能与其他所有人成为好友的概率,对 \(998244353\) 取模。

数据范围:\(1\le k\le n\le 10000,0\le p<998244353\)

\(f_i\) 实际上就是 \(1-\) 中间那一个长式子。

\(g_j\) 也可以直接暴力求,幂次相关的都可以预处理。

求组合数的时候少写那一个 if 判断为什么时间快那么多啊/fad。

代码:https://paste.ubuntu.com/p/j86dRTqkHJ/

The 1st Universal Cup. Stage 7: Zaporizhzhia 部分题目

3.12

[洛谷 P9147] 签到题(DP + 枚举)

[洛谷 P9148] 除法题(差分 + 前缀和 + 枚举倍数)

[洛谷 P9149] 串串题(KMP + 组合计数 + 树状数组)

3.13

[ARC158C] All Pair Digit Sums(枚举 + 排序)

题面

假设 \(x+y\) 中有 \(k\) 个进位,那么 \(f(x+y)=f(x)+f(y)-9k\)

所以可以将所求变为 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n f(a_i)+f(a_j)-9k\)

前两项是好算的,即为 \(2n\sum\limits_{i=1}^n f(a_i)\)

对于进位,考虑对每一位单独来考虑。设 \(b_i=a_i\bmod 10^{l+1}\)

那么如果 \(b_i+b_j\ge 10^{l+1}\),就说明这一位可以进位。

所以我们只需要将所有 \(b_i\) 排序,双指针求一下有多少个可以进位就行了。

代码:https://paste.ubuntu.com/p/Z4htbB9RH4/

[CF1804F] Approximate Diameter(二分 + BFS)

题面

定义:

  • \(dis_G(i,j)\) 表示图 \(G\)\(i,j\) 的最短路。
  • \(c_G(i)=\max\limits_{j=1}^n dis_G(i,j)\)
  • \(d(G)=\max\limits_{i=1}^n c_G(i)\),表示图 \(G\) 的直径。
  • \(r(G)=\min\limits_{i=1}^n c_G(i)\),表示图 \(G\) 的半径。

\(v\) 是图 \(G\) 上的任意一点,有:

\[\frac{d(G)}{2} \leq r(G) \leq c_G(v) \leq d(G) \leq 2 \cdot r(G) \leq 2 \cdot c_G(v) \leq 2 \cdot d(G) \]

性质:\(d_i(G)\) 不增。证明显然。

所以可以对于某一个当前得到的 \(c_{G_i}(v)\),二分出一个最大的 \(c_{G_j}(v)\) 满足 \(2\cdot c_{G_j(v)}\ge c_{G_i}(v)\),将 \(i\sim j\) 的答案全部设为 \(c_{G_i}(v)\)

代码:https://paste.ubuntu.com/p/Q7XHPc4zQM/

[ARC147E] Examination(贪心 + 堆)

题面

如果我们确定了哪些学生要交换分数,那么最优方案肯定是将他们的 \(A_i\) 从小到大排序去和 \(B_i\) 从小到大排序的结果比较,所有的 \(A_i\ge B_i\) 才说明这是一组合法方案。

用两个小根堆来维护所有要交换分数的学生的 \(A\)\(B\)

对于所有 \(A_i<B_i\) 的学生,他们肯定需要交换分数,将他们放入小根堆中。如果这一对 \(A_i\)\(B_i\) 已经满足 \(A_i\ge B_i\) 了就直接跳,否则我们就要从合法的数对里引进一对数来使这一对 \(A_i\)\(B_i\) 满足条件。可以发现我们引进的数对必须要满足 \(B_j\le A_i\) 的同时 \(A_j\) 最大,然后交换 \(A_i\)\(A_j\) 即可。可以一个大根堆维护满足 \(B_j\le A_i\)\(A_j\)

代码:https://paste.ubuntu.com/p/bPTDtH7KCp/

[ARC148E] ≥ K(组合计数 + 排列计数)

题面

对于这种对相邻两个元素都有影响的问题,可以考虑将元素按一定顺序一个个加入序列,考虑其对整个方案数的贡献。

将所有元素从小到大排序。

考虑两个维护左右区间的指针 \(l,r\),令 \(a_r\)\(a_l+a_r\ge k\) 的最小编号,其中 \([1,l-1]\) 以及 \([r+1,n]\) 这两段中的元素都已经加入序列。

这样就可以知道一共加入了 \(n-r+l-1\) 个元素,有 \(n-r+l\) 个空位可供下一个元素放置。

  • 放入 \(a_r\)

    此时一共有 \(l-1\) 个元素无法满足将 \(a_r\) 放入其左边或者右边时满足 \(\ge k\) 的要求(之所以是 \(l-1\) 是因为既然 \(r\) 并没有在 \(l\) 之前的元素遍历到时就放入,那么自然前面的元素也是不满足条件的);

    那么此时就有 \((n−r+l)−2\times(l−1)\) 个空位可选。

  • 放入 \(a_l\)

    \([1,l−1]\) 中的元素和 \(a_l\) 也不能满足条件;

    不会有 \(a_l+a_{l-1}\ge k\),因为如果这样的话 \(a_l\) 就会在遍历到 \(l\) 还是 \(l-1\) 时就被当作 \(a_r\) 放入;

    同理,有 \((n−r+l)−2\times(l−1)\) 个空位可选。

  • 注意,因为有相同元素,因此要在最后除以相同元素的排列数以消除影响。

代码:https://paste.ubuntu.com/p/5358JM7ZmM/

3.14

2023.3.11 考试 T3 01 串 / [CF794G] Replace All(性质 + 组合计数 + 数学)

题面

先考虑没有 ? 的情况。

如果两个字符串相等,那么任意一种替换方法都可行,答案为 \((\sum\limits_{i=1}^n2^i)^2\)

关键性质:\(A\)\(B\) 都可以表示成另一个串 \(C\) 的重复出现若干次的形式。

证明可见洛谷题解区,类似更相减损的过程。

显然这个串 \(C\) 的长度为 \(\gcd(|A|,|B|)\)

那么答案就只与 \(S,T\)\(A,B\) 出现的次数有关。

首先肯定要满足 \(|A|\times cntA_S+|B|\times cntB_S=|A|\times cntA_T+|B|\times cntB_T\),移项之后得到 \((cntA_S-cntA_T)|A|=(cntB_T-cntB_S)|B|\)

\(a=cntA_S-cntA_T\)\(b=cntB_T-cntB_S\)

如果 \(a,b\) 异号,显然答案为 \(0\)

如果 \(a=b=0\),那么 \(|A|,|B|\) 的长度任意,答案为 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n2^{\gcd(i,j)}\),可以枚举 \(\gcd\) 之后用欧拉函数 \(\varphi\) 快速算出。

否则 \(a\ne b\),可以先约分到 \(a,b\) 互质的情况,然后枚举长度,答案为 \(\sum\limits_{i=1}^{\lfloor\frac{n}{\max(a,b)}\rfloor}2^i\)

再考虑有 ? 的情况。设 \(f_{a,b}\) 表示上面的答案。

显然我们只关心有多少个 ? 变成了 \(A\),多少个 ? 变成了 \(B\)。设 \(S\) 中有 \(x\)?\(T\) 中有 \(y\)?

枚举可以得到:

\[\begin{aligned} &\sum\limits_{i=0}^x\sum\limits_{j=0}^yf_{a+i-j,b+(y-j)-(x-i)}\binom{x}{i}\binom{y}{j}\\ =&\sum\limits_{k=i-j=-y}^xf_{a+k,b+k+y-x}\sum\limits_j\binom{x}{k+j}\binom{y}{y-j}\\ =&\sum\limits_{k=-y}^xf_{a+k,b+k+y-x}\binom{x+y}{y+k} \end{aligned} \]

可以直接计算了。

最后要特判一下两个字符串相等的情况的贡献。

代码:https://paste.ubuntu.com/p/wVGKgDbdBS/

2023.3.14 考试 T2 海蛎海螺海胆(seafood)(树链剖分 + 二分 + 树状数组)

题意:

给定一棵 \(n\) 个节点的以 \(1\) 为根的有根树,每个点有点权 \(a_i\),初始所有 \(a_i=0\)

每一个时刻有两种变化之一发生:

  • 1 u x,将 \(u\) 子树内的点的点权全部加上 \(x\)
  • 2 u v x,将 \(u\to v\) 路径上的点的点权全部加上 \(x\)

求每个时刻变化之后树的深度最小的带权重心的编号。

带权重心定义:\(\sum\limits_{i=1}^n dis(i,u)\times a_i\) 最小的点 \(u\)

数据范围:\(2\le n\le 10^5,1\le q\le 10^5\)

代码:https://paste.ubuntu.com/p/mf9BZbJVbN/

3.15

[ARC149E] Sliding Window Sort(性质 + 组合计数)

题面

nb 题。

题意是说将一段长度为 \(m\) 的区间排序之后,将窗口右移一位。可以转化为排序之后窗口不动,序列循环左移一位。

然后将前 \(m-1\) 个元素和后 \(n-m+1\) 个元素单独考虑。

剩下的可以见 https://www.cnblogs.com/cjjsb/p/16754829.html

代码:https://paste.ubuntu.com/p/yZG74xhNwc/

[ARC146D] >=<(转化题意 + 贪心)

题面

条件可以转化为:\(a_{p_i}\le x_i-1\iff a_{q_i}\le y_i-1\)\(a_{p_i}\le x_i\iff a_{q_i}\le y_i\)

首先初始 \(a\) 所有元素为 \(1\) 。不断约束使得 \(a\) 符合条件。

然后对于一个个条件不断更新:如果 \(a_{p_i}\) 大于 \(x_i\),那么 \(a_{q_i}\) 就更新为 \(\max(a_{q_i},y_i+1)\)。同理 \(a_{q_i}\) 大于 \(y_i\) 也对 \(a_{p_i}\) 做类似处理。这个用排序 + 类似 SPFA 的方式去做就行了。

最后判断一下在 \(m\) 的值域之内即可。

这样做的正确性显然:增量法,假设之前已经构造出了最优解,这两个元素无疑是最小的。如果符合条件就无需变动,否则就取一个对于两者都最小的不符合值域的值。

代码:https://paste.ubuntu.com/p/2msjtXzxRj/

[ARC146C] Even XOR(性质 + DP + 计数)

题面

题意即为:所有大小为偶数的子集的异或和不为 \(0\)

可以转化为:不存在元素个数奇偶性相同的两个子集(不相同)的异或和相等。

推论:不存在大小 \(>n+1\) 的合法集合。

证明:一个大小为 \(x\) 的集合分别有 \(2^{x-1}\) 个大小为奇数和偶数的集合。如果 \(x>n+1\),那么 \(2^{x-1}>2^n\),根据抽屉原理一定会有两个不同的奇偶性相同的子集的异或和相等。

这样元素个数就变成了 \(\mathcal{O}(n)\) 级别,可以考虑与元素个数相关的 DP。

\(dp_i\) 表示大小为 \(i\) 的合法集合数量。边界显然 \(dp_0=1,dp_1=2^n\)

加入一个数之后,它不能和之前某一个大小为奇数的集合异或和相同,而我们这个性质保证了所有奇偶性相同的集合异或和不同,所以它有 \(2^n-2^{i-2}\) 种选择方式。因为这个转移是有顺序的,所以还要乘 \(\frac{1}{i}\) 的系数。转移:\(dp_i=dp_{i-1}\times(2^n-2^{i-2})\times\frac{1}{i}\)

代码:https://paste.ubuntu.com/p/Zbf8Mgrv2h/

[ARC128E] K Different Values(贪心)

题面

题意:

给定一个长度为 \(n\) 的序列 \(a\),构造一个字典序最小的序列 \(x\) 满足:

  • 对于每个 \(a_i\)\(x\) 满足包含 \(a_i\)\(i\),且 \(x\) 不包含除 \(1\sim n\) 以外的其他数。
  • 对于 \(x\) 中任意的长度为 \(K\) 的连续段,段中的值互不相等。

若无解则输出 -1

数据范围:\(2\le K\le n\le 500,\sum a_i\le 2\times10^5\)

\(x\) 序列分块,每一块大小为 \(K\),共分了 \(c\) 块,最后一块大小为 \(g\le K\)

那么有解的充要条件就是 \(\forall 1\le i\le n,a_i\le c\)\(\sum[a_i=c]\le g\)。证明显然,考虑相邻两个相同的数的位置差要 \(\ge K\)

然后从前往后贪心,考虑 fix 一段前缀最优。具体见洛谷题解区。

代码:https://paste.ubuntu.com/p/hfgKsbvWp2/

[ARC127E] Priority Queue(充要条件 + DP)

题面

完全想不到啊。

考虑对于 \(1\le v\le n\),怎么让最终 \(S\) 集合里 \(\ge v\) 的数的数量最多。

显然只需要在第 \(i\) 次加入操作时加入数 \(i\) 就能达到目的。

假设这样最终得到的集合为 \(Z\),那么一个集合 \(X\) 合法的充要条件就是:将 \(X\)\(Z\) 中的数从小到大排序之后,\(\forall 1\le i\le a-b,X_i\le Z_i\)

知道这个结论之后我们就可以很方便地 DP 了:设 \(f_{i,j}\) 表示 \(X\) 集合里选了 \(i\) 个数,且 \(X_i=j\),满足条件的方案数。转移直接前缀和优化一下可以做到 \(\mathcal{O}(a^2)\)

证明可见官方题解:https://atcoder.jp/contests/arc127/editorial/2696。还是有点巧妙的!

代码:https://paste.ubuntu.com/p/mt4TjQjjRT/

感觉这种题完全想不到啊啊啊???

3.16

2023.3.16 考试 T1 Educational / [CF908G] New Year and Original Order(贡献法 + DP + 二项式定理 + 推式子)

题面

数据范围:\(1\le n<10^{10000}\)

对于题面里这种贡献的计算方式,可以看成 \(9\) 个形如 \(111\dots11\) 这样的数相加。例如 \(f(32134)=12334=11111+1111+111+1+0+\dots+0\)。也就是说设 \(s_i\) 表示 \(\ge i\) 的数位个数,那么 \(f(x)=\frac{1}{9}\sum\limits_{i=1}^9(10^{s_i}-1)\)

考虑 fix 一段前缀和 \(n\) 相等,钦定下一位比 \(n\) 小,然后就是后面若干项随便取。

对于若干位随便取的贡献,设前面已知的有 \(cnt_i\)\(\ge i\) 的数位,后面有 \(m\) 位待填,那么每一个数位 \(i\) 的贡献为:

\[\begin{aligned} &\frac{1}{9}\sum\limits_{p=0}^m\binom{m}{p}i^{m-p}(10-i)^p(10^{cnt_i+p}-1)\\ =&\frac{1}{9}\times10^{cnt_i}\times\sum\limits_{p=0}^m\binom{m}{p}i^{m-p}(10-i)^p10^p-\frac{1}{9}\sum\limits_{p=0}^m\binom{m}{p}i^{m-p}(10-i)^p\\ =&\frac{1}{9}\times10^{cnt_i}\times(100-9i)^m-\frac{1}{9}\times10^m \end{aligned} \]

幂次相关的计算都可以预处理。

时间复杂度 \(\mathcal{O}(k^2n)\)

代码:https://paste.ubuntu.com/p/vTWWWMhNsX/

[ARC137E] Bakery(最小费用循环流)

题面

题意:

规划面包店,天数为 \(1\sim n\)。有 \(m\) 位面包师,编号为 \(1\sim m\),雇用 \(i\) 的成本为 \(c_i\),然后他会在 \(l_i\sim r_i\) 天每天做一个面包。第 \(i\) 天面包师一共做了 \(x_i\) 个面包的话,售出的就是 \(\min(a_i,x_i)\) 个面包。每个面包获利 \(d\),求最大利润(售出面包的获利减去雇用面包师的开支)。

数据范围:\(1\le n,m\le 2000,1\le d,c_i\le 10^9\)

显然考虑费用流。然而如果用面包来流不太好考虑面包师的开支。

那么我们就只能用面包师来流了。

考虑建图,点编号为 \(0\sim n\)

  • \((i,i-1,a_i,-d)\),表示产生贡献的面包。
  • \((i,i-1,m-a_i,0)\),表示没有产生贡献的面包。
  • \((l_i-1,r_i,1,c_i)\),表示面包师的开支。

然后跑最小费用循环流就是答案。也就是消负环。实际上就是预先加入负权边满流时的贡献,然后退流。具体可见 https://blog.csdn.net/neweryyy/article/details/105792033

然而本题中对于 \(1\sim n-1\) 的点不需要与源点 / 汇点连边,因为对于其中的每个点 \(i\) 都会连边 \(S\to i\to T\),而这两条边一定会满流且不影响费用。

所以连边方式如下:

  • \((i-1,i,a_i,d)\)
  • \((i-1,i,m-a_i,0)\)
  • \((l_i-1,r_i,1,c_i)\)
  • \((S,0,m,0),(n,T,m,0)\)

然而卡 SPFA 费用流,要用原始对偶算法,方便可以直接用 ACL 库。

代码:https://paste.ubuntu.com/p/57HWcCZsdQ/

2023.3.15 考试 T1 希望(hope) / [洛谷 P9060] [Ynoi2002] Goedel Machine(根号分治 + 莫队)

题面

启发:当贡献和质因子次数有关时,可以考虑按质数大小根号分治。

代码:https://paste.ubuntu.com/p/dwt2NzstZw/

3.17

[洛谷 P9058] [Ynoi2004] rpmtdq(点分治 + 单调栈 + 扫描线 + 树状数组)

题面

最近点对问题有一个通用思路,就是找“支配点对”,也就是说,有许多的点对是没有用的。

由于树上距离涉及路径,我们可以思考点分治。对于一次分治,我们要思考这个连通块两两之间有哪些是会计入最终有效点对的。

对于当前分治中心内的所有点 \(u\),求出 \(dis_u\) 表示 \(u\) 到分治中心的距离。那么对于任意两点 \(u,v\) 均有 \(dis_u+dis_v\ge dis(u,v)\)。取到等号当且仅当 \(u,v\) 在分治中心的不同子树内。

分析一下哪些点对 \((i,k)\) 可能是有效点对。\((i,k)\) 需要满足 \(\forall i<j<k,dis(i,k)<dis(j,k),dis(i,k)<dis(i,j)\),也就是 \(dis_i<dis_j,dis_k<dis_j\),即 \(\max(dis_i,dis_k)<\min\limits_{j=i+1}^{k-1}dis_j\)

考虑怎么快速求出所有有效点对。可以将点按照 \(dis\) 从小到大加入一个 set 中,每次加入一个点 \(p\) 时,\(p\) 和它的前驱 & 后继就是两个有效点对。这样分析可以知道有效点对总数是 \(\mathcal{O}(n\log n)\) 的。

不过这样会被卡常,我们需要更快速的做法。我们发现这个过程等价于按 \(p\) 排序,维护 \(dis_p\) 不减 的单调栈,按照 \(p\) 顺序加入 \(dis_p\),从栈顶弹出所有大于 \(dis_p\) 的数之后,设栈顶为 \(dis_u\),那么 \((u,p)\) 就是一个有效点对。正反都做一遍就行了。

求出所有有效点对之后,考虑如何回答询问。

每次在编号较大的那一个点的位置加入有效点对。扫描线维护一个数组 \(t\),加入有效点对 \((i,j)\)\(i<j\))时 \(t_i\leftarrow\min(t_i,dis(i,j))\)。在 \(r\) 处插入询问,答案是一个后缀 \(\min\) 的形式。单点取 \(\min\) & 求后缀 \(\min\) 可以用树状数组来维护。

代码:https://paste.ubuntu.com/p/3qrc2TXzDf/

[NOIP2022] 比赛(分治 + 线段树)

题面

有一种非常厉害的分治做法。

先考虑前 \(52\) 分的情况。我们可以把每次询问都拿出来做一次分治。

考虑跨过区间中点 \(mid\) 的贡献。预处理出 \(la_i=\max\limits_{j=i}^{mid}a_j\)\(ra_i=\max\limits_{j=mid+1}^i a_j\)\(lb_i=\max\limits_{j=i}^{mid}b_j\)\(rb_i=\max\limits_{j=mid+1}^i b_j\),那么对于区间 \([i,j]\),它的贡献就是 \(\max(la_i,ra_j)\times\max(lb_i,rb_j)\)

枚举 \(j\),找到一个最大的位置 \(x\) 满足 \(la_x>ra_j\),即 \(i\in[x+1,mid]\) 时左边的 \(\max\) 取到 \(ra_j\)\(i\in[l,x]\) 时取到 \(la_i\);同样的找到一个最大的位置 \(y\) 满足 \(lb_y>rb_j\)。那么 \(x\)\(y\) 就将左半部分的贡献分成了三部分:

  • \([l,\min(x,y)]\) 的贡献为 \(la_i\times lb_i\)
  • 如果 \(x\le y\),那么 \([x+1,y]\) 的贡献为 \(ra_j\times lb_i\);否则 \([y+1,x]\) 的贡献为 \(la_i\times rb_j\)
  • \([\max(x,y)+1,mid]\) 的贡献为 \(ra_j\times rb_j\)

分别记录三个前缀和就可以快速求出所有贡献和。

接下来考虑满分做法。类似线段树分治,我们把询问挂在区间上。也就是说,如果当前询问为 \([l,r]\),当前递归到的区间为 \([i,j]\),那么如果 \(l\le i\le j\le r\),就挂上去直接返回。如果询问跨过了中点,就挂在这个点上并往左右子区间递归。如果没跨过中点就往询问所在的子区间递归。

然后在分治的时候,我们分别开四棵线段树去维护每一种贡献。具体的,在枚举的右端点右移的过程中,把所有与 \(j\) 相关的量在线段树上加入贡献,对询问的贡献可以考虑把询问挂在右端点处统计贡献和。

时间复杂度 \(\mathcal{O}((n+Q)\log^2 n)\)。常数略大,擦着时限过去的/qd。

代码:https://paste.ubuntu.com/p/JgCHp2ZPtB/

不要干想最值分治去了然后忘了普通分治……

2023.3.17 考试 T2 跳水(jump) / [洛谷 P3549] [POI2013]MUL-Multidrink(构造 + DP)

题面

阴间码农题。

考虑直接 DP,然后按照转移输出路径。

剩下的可见 https://www.cnblogs.com/A-zjzj/p/17058936.html

有点复杂。

代码:https://paste.ubuntu.com/p/mXvzJDrH7N/

3.18

2023.3.18 考试 T1 内鬼(game)(DP + 迭代)

题意:

你是一名经验丰富的 OIer,普通的有向图游戏已经不能满足你的胃口。

于是你叫来了 \(k\) 位 OI 选手分成两队帮你玩游戏。具体地,给定任意一张 \(n\) 个点 \(m\) 条边有向图,其中一个节点上有一颗棋子。游戏会进行若干轮,第 \(i\) 轮第 \((i − 1) \bmod k + 1\) 位选手将会移动这颗棋子,每次可以将它移动向一个当前节点的后继节点。直到某一轮轮到了一个人无法操作,那么这个人所属的队伍将会失败。

然而你仍然觉得这个题很套路,于是你在这两队的选手之中安插了一些内鬼,内鬼将会以让自己所属的队伍失败为目标进行操作。

由于 OIer 们都知道如何解决有向图游戏,所以大家都会按照对自己最优的策略移动。

注意到图中可能有环,在游戏会进行无限轮的情况下认为达成平局。上述“对自己最优的策略”指的是在无法达成自己的目标时尽可能地尝试达成平局。

现在你想要知道的是,对于每一个 \(x \in [1, n]\),当初始棋子被放在 x 号节点时最终哪个队会获胜或者出现平局。

数据范围:\(1\le n,m\le 5\times 10^5,2\le k\le 6\)

代码:https://paste.ubuntu.com/p/Y5wPv8HnBB/

3.19

JOISC 2023 Day1 T1(整体二分 + 树链剖分 + 树状数组)

JOISC 2023 Day1 T3(线段树优化连边 + 最短路)

[洛谷 P7984] [USACO21DEC] Tickets P(线段树优化连边 + 最短路)

题面

JOISC 2023 Day1T3 就是这题的弱化版(虽然这题也没加强到哪去)。

考虑把每张票看成一个虚点,从 \(c_i\)\(i\) 这张票连边,然后这张票向 \([a_i,b_i]\) 连边。后者可以用线段树优化连边。

答案实际上就是每个点到 \(1\) 的距离加上到 \(n\) 的距离,可以直接建反图然后从 \(1\)\(n\) 开始跑最短路。然而这个时候可能会算重贡献,即同时存在于两条最短路上的边的代价会算两次,只需要将每个点的答案单独拿出来再跑一遍最短路就行了。具体见代码。

代码:https://paste.ubuntu.com/p/DPRdkTN8C8/

posted @ 2023-03-08 07:57  csxsi  阅读(11)  评论(0)    收藏  举报