2022 联赛做题记录 1.0

目录

这里面没写题解的题要么就是在别的文章里写过了,要么就是太水了不想写……

8.30

「CF1592F1」Alice and Recoloring 1(思维)

题面

首先发现操作 2、3 可以被若干次操作 1 替代,代价不劣。

一种非常妙的转化:设 \(a_{i,j}=[s_{i,j}=\texttt{B}]\)\(b_{i,j}=a_{i,j}\oplus a_{i+1,j}\oplus a_{i,j+1}\oplus a_{i+1,j+1}\),那么选择的子矩阵的另一顶点是 \((i,j)\),执行操作 1 就相当于反转 \(b_{i,j}\),执行操作 4 就相当于反转 \(b_{i-1,j-1},b_{i-1,m},b_{n,j-1},b_{n,m}\)。将全部 \(a_{i,j}\) 变成 \(0\) 的充要条件是所有 \(b_{i,j}=0\)

不难发现操作 4 最多执行 1 次,因为两次或以上操作 4 都可以被次数更少的操作 1 替代。

所以只需要看有多少个 \(b_{i,j}=1\),并且再看有没有一个能使用操作 4 的 \(b_{i,j}\) 就行了。

核心就在于那一个转化,非常巧妙。

代码:https://pastebin.ubuntu.com/p/FybC2d8QNC/

9.3

「HDU7258」2022 CCPC 华为云计算挑战赛 - 直播(二分 + 状压枚举 + 网络流)

题面

很明显可以二分答案,然后就可以得出每条边最多能被多少条路径经过。

注意到我们 最多只有 5 个 CDN 节点。而且只有 CDN 节点是出边随便流的,因此考虑枚举 CDN 节点的使用情况。

注意数据范围很网络流,而且问题也类似一种分配的方式,所以考虑如何建图。

把原图中 \(n\) 个点拿出来作一列,CDN 节点单独拿出来作另一列,先把与 CDN 节点无关的边加入,流量为最多能被经过的路径数量,然后将 \(v_i=2\) 的节点向汇点连流量为 \(1\) 的边。

枚举哪一些 CDN 节点要被使用,设其中的一个点是 \(i\)。那么就将 \(i\) 向汇点连流量为 \(1\) 的边,把原图中出点是 \(i\) 的边加入,将 \(i+num\)\(num\)\(i\) 在 CDN 节点中编号排序后是第几个,也就是离散化后的编号)向原图中 \(i\) 的出边的另一顶点连流量为 \(\inf\) 的边。判断就是图是否满流。

画一下图可能更容易理解。

代码:https://pastebin.ubuntu.com/p/hxywPwTH2q/

「HDU7261」2022 CCPC 华为云计算挑战赛 - 信道定向(构造 + 欧拉回路)

题面

不难发现下界就是 \(\max(\lceil\frac{du_i}{2}\rceil)\),可以通过构造证明下界可达。

\(0\) 与度数为奇数的点连边,然后求出这张图的欧拉回路,那么它一定是满足条件的。

因为 HDU 会爆栈,所以要用栈模拟 DFS。

代码:https://pastebin.ubuntu.com/p/5wM538RBND/

「NOI2022」众数(摩尔投票法 + 线段树合并 + 链表)

题面

我考场上怎么没做出来??????????????????????????

对于绝对众数,考虑摩尔投票法,就是线段树记录区间内的绝对众数,pushup 的时候很好合并。

删除与合并都可以用链表 + 线段树合并。

查询同样,重载一下 pair 类型的 + 运算符即可。

代码:https://pastebin.ubuntu.com/p/BMKbw2XQH3/

9.6

「ABC267D」Exactly K Steps(直径的性质)

题面

到一个点距离最远的点一定是两个直径端点之一,那么直接 dfs 即可。

代码:https://pastebin.ubuntu.com/p/nDp4j2zsd3/

「NOI2022」挑战 NPC Ⅱ(树哈希 + 爆搜)

题面

题目明示树哈希,于是考场上直接暴力树哈希 76pts 走人。

树哈希推荐转化成括号序列的写法。

殊不知,这题的正解其实也很简单。我们从上到下 dfs 依次尝试匹配,子树能匹配的就直接匹配,对于多的点我们可以 \(k!\) 暴力枚举它们在哪棵子树下。

代码:https://pastebin.ubuntu.com/p/rd9tDF6qM4/

9.11

洛谷 P6748 『MdOI R3』Fallen Lord(2022 ZR noip 十连测 day3 T2,树形 dp + 贪心)

9.12

2021 百度之星・程序设计大赛 - 复赛 A~C & E

「LOJ3276」「JOISC 2020 Day2」遗迹(2022 ZR noip 十连测 day3 T4,难度比较大的计数 dp)

9.13

「CF1726E」Almost Perfect(性质 + 计数)

题面

发现满足条件的置换中的环只有可能存在以下情况:

  • 一元环;
  • 二元环;
  • 两种四元环中的一种:
    • \(p_i=j+1,p_{j+1}=i+1,p_{i+1}=j,p_j=i\)
    • \(p_i=j,p_j=i+1,p_{i+1}=j+1,p_{j+1}=i\)

对于前两种,很好计数:设 \(f_i\) 为长度为 \(i\) 的置换全都是一元环或二元环的数量,则有 \(f_i=f_{i-1}+(i-1)f_{i-2}\)

考虑枚举四元环个数 \(k\),那么就相当于在 \(1\sim n-1\) 中选出 \(2k\) 个不相邻的数作为 \(i,j\)。我们设 \(x_1,x_2,\dots,x_{2k},x_{2k+1}\) 表示相邻两项的间隔(其中 \(x_1\)\(1\) 到第一个数的距离,\(x_{2k+1}\)\(n-1\) 到最后一个数的距离),有:

\[x_1,x_{2k+1}\ge 0\\ \forall 1<i\le 2k, x_i>0\\ \sum x_i=n-1-2k \]

\(x_1\)\(x_{2k+1}\) 加上 \(1\),就可以使得 \(\forall i,x_i>0\)\(\sum x_i=n-2k+1\)

这个方案数可以使用隔板法方便地算出,即为 \(\binom{n-2k}{2k}\)

然后,对于划分 \(i,j\),我们可以先将 \(2k\) 个元素任意排列,两两看成一组。对于组内的,如果 \(i<j\) 就是第一种,否则就是第二种。因为组之间没有顺序,所以这一部分方案数就为 \(\frac{(2k)!}{k!}\)

所以答案为 \(\sum\limits_{i=0}^{\lfloor\frac{n}{4}\rfloor}\binom{n-2i}{2i}\frac{(2i)!}{i!}f_{n-4i}\)

代码:https://pastebin.ubuntu.com/p/3VfW5cZVQK/

「ABC267G」Increasing K Times(排列计数 dp)

题面

题意:

给一个长度为 \(n\) 的序列 \(\{a\}\),要求有多少个排列 \(p\) 满足:

  • 恰好有 \(k\)\(i\in [1,n-1]\) 满足 \(a_{p_i}<a_{p_i-1}\)

\(998244353\) 取模。

数据范围:\(2\le n\le 5000,0\le k<n,1\le a_i\le n\)

对于排列计数,一般考虑按照某种顺序加入数字。

本题中,我们考虑从小到大加入 \(a\) 中的数字。

先在最终的序列左右两侧各加入一个 \(0\)。那么新加入一个数 \(x\) 插在 \(i\)\(i+1\) 之间,上升段增加的条件是 \(x>a_i\ge a_{i+1}\)

注意到 \(x\) 的数量其实就是长度减去上升段的数量,再减去当前序列中与 \(x\) 相等的数的个数。

所以就有:设 \(f_{i,j}\) 表示加入了排序后的前 \(i\) 个数,有 \(j\) 个上升段的方案数。

转移显然。

代码:https://pastebin.ubuntu.com/p/BkrmXkdhkz/

「QOJ4240」「Discover Singapore 2019 by Moscow Workshops. Day 5. 300iq Contest」Tree Circles(Kruskal 重构树 + 倍增 + 树状数组)

「QOJ4238」「Discover Singapore 2019 by Moscow Workshops. Day 5. 300iq Contest」Zero Sum(随机化 + dp)

「QOJ4241」「Discover Singapore 2019 by Moscow Workshops. Day 5. 300iq Contest」Angle Beats 2.0(很强的神必思维题)

Petrozavodsk Winter 2020. Day 3. 300iq Contest 3 B(结论) & I(位运算)

9.14

Good Bye 2018 A~F

「ARC146C」Even XOR(性质 + dp)

「ABC268F」Best Concatenation(邻项交换 + 贪心)

题面

把相邻两项的贡献式写出来,发现按照 \(\frac{字符串内所有数字的和}{字符串内 \texttt{X} 的个数}\) 从小到大排序是最优的。

代码:https://pastebin.ubuntu.com/p/yFy84xS37Y/

「ABC268G」Random Student ID(trie 树 + 期望的性质)

题面

把 trie 树建出来,对于一个串,它所有祖先的字典序一定小于它,它所有后代的字典序一定大于它,其它的小于它的概率是 \(\frac{1}{2}\)。证明考虑 fix 一段相等的前缀,下一个字符一定是 \(\frac{1}{2}\) 的概率前者比后者大。

那么 trie 树上一个节点的期望字典序就是 \(1+anc+\frac{1}{2}\times(n-anc-size)\),其中 \(anc\) 为祖先里的结尾节点数量,\(size\) 为子树里的结尾节点数量。

代码:https://pastebin.ubuntu.com/p/6772fHCqvs/

「ABC266G」Yet Another RGB Sequence(容斥原理)

题面

把两个相邻的 RG 绑在一起,然后容斥原理枚举至少有 \(k+i\)RG,再套上一个可重集排列就行了。

代码:https://pastebin.ubuntu.com/p/PwSMcNJtCY/

「ABC265F」Manhattan Cafe(dp 优化)

题面

首先有一个 \(\mathcal{O}(nd^3)\) 的朴素 dp:设 \(f_{i,j,k}\) 表示前 \(i\) 维,\(r\)\(p\) 的距离和为 \(i\)\(r\)\(q\) 的距离和为 \(j\) 的方案数,转移就是暴力枚举 \(r\) 的这一维填什么。

考虑优化这个转移:注意到转移到 \((i,j)\)\((i',j')\) 只会有以下三种形式:

  • \(r\) 这一维 \(<\min(p_i,q_i)\) 或者 \(>\max(p_i,q_i)\),此时满足 \(i'-j'=\pm |p_i-q_i|\)
  • \(r\) 这一维 \(\in[\min(p_i,q_i),\max(p_i,q_i)]\),此时满足 \(i'+j'=|p_i-q_i|\)

容易发现这是三段一次函数的式子,可以前缀和优化朴素 dp。

代码:https://pastebin.ubuntu.com/p/tYWDZrP45g/

9.15

2022.9.15 联考 T1 T2 T3 T4

「CF19D」Points(set + 线段树二分)

题面

首先肯定是离散化,然后拿 set 维护每一个横坐标对应的点的纵坐标,用一棵线段树维护一段横坐标区间的纵坐标最大值。

查询的时候在线段树上二分即可。

代码:https://pastebin.ubuntu.com/p/fdCPrdhfcy/

「CF1327F」AND Segments(dp + 前缀和优化)

题面

其实是一道经典老题。

显然可以拆位做。于是限制就变成了一个区间必须全是 \(1\) 或者至少有一个是 \(0\)

\(f_{i,j}\) 表示考虑了前 \(i\) 位,上一个填了 \(0\) 的位置是 \(j\) 的方案数。

首先可以求出来每个位置是否强制填 \(1\),以及它上一个 \(0\) 的位置最远是多少,不妨设为 \(pos_i\)

转移:

  • 若第 \(i\) 位填的是 \(1\),那么:
    • \(f_{i,j}=0(0<j<pos_i)\)
    • \(f_{i,j}=f_{i-1,j}(pos_j\le j<i)\)
  • 若第 \(i\) 位填的是 \(0\),那么 \(f_{i,i}=\sum\limits_{k=pos_i}^{i-1}f_{i-1,k}\)

不难发现推进一次 \(i\) 只会使一个前缀变成 \(0\) 或者改变 \(f_{i,i}\) 的值。

那么我们可以实时维护 \(\sum\limits_{k=pos_i}^{i-1}f_{i-1,k}\),具体的用指针扫一遍就行了。

答案就是每一位的方案数乘起来。

代码:https://pastebin.ubuntu.com/p/vCJ7k3YV8D/

9.16

「CF1327G」Letters and Question Marks(AC 自动机 + dp)

题面

先把所有 \(t_i\) 的 AC 自动机建出来,然后记录一下每个点对应 trie 树上后缀的字符串权值之和 \(sn_i\)

\(f_{i,j}\) 表示当前在 trie 树上的第 \(i\) 个节点,现在选了的字符集合是 \(j\)

不难发现 ? 把整个字符串分成了若干段,其中每一段的转移都类似,即 \(f_{i,j}+sn_{trans_{i,s_k}}\to f_{trans_{i,s_k},j}\)。这个可以直接预处理出来。

对于 ? 的转移,我们可以单独拿出来考虑。

总的来说,这道题目的思路还是比较明显的,就是代码可能有点长。

代码:https://pastebin.ubuntu.com/p/nmfM32ntTz/

9.17

SWERC 2021-2022 A & C & D & F & I & L & N

9.18

今日初赛……各种神奇挂法,可能 \(80\) 不到……寄飞!!!!!!!!!!!!!!!!!!1111

「CF1712F」Triameter(启发式合并)

题面

这是一道好题阿。

考虑加边之后,\(d(u,v)=\min(dis(u,v),f_u+f_v+x)\),其中 \(dis(u,v)\)\(u\)\(v\) 的树上距离,\(f_u\)\(u\) 到最近的叶子节点的距离。原因显然。

问题的关键来了:求树上与两点距离有关式子的最值可以考虑启发式合并,因为合并子树的时候两点的 \(\bf{LCA}\) 就是当前 dfs 到的点

考虑维护一个 \(vec_{u,i}\) 表示 \(u\) 子树内 \(f=i\) 的点的最大深度。

那么合并的时候可以直接取 \(\max\)

对于求解答案,我们每一次启发式合并的时候就遍历每一个询问,看这个询问的答案能否 \(+1\)。具体的,当我们合并 \(u\)\(v\) 时(\(size_{vec_u}>size_{vec_v}\)),枚举 \(i:0\sim size_{vec_v}-1\),当 \(j=\max(0,ans+1-i-x)<size_{vec_u}\)\(dis(vec_{u,j},vec_{v, i})\ge ans+1\) 时,\(ans\) 就可以 \(+1\)

为什么呢?因为此时若选择 \(vec_{u,j}\)\(vec_{v,i}\) 对应的点,那么 \(dis\ge ans\) 并且 \(j+i+x=ans\),满足条件。

秒极!!!!!!!!!!!!!!!!!!!!!11

代码:https://pastebin.ubuntu.com/p/pjXCBt75MT/

9.19

2022.9.19 考试 T1 T2 T3 T4

「CF1479D」Odd Mineral Resource(随机化 + 主席树二分)

题面

好题啊。

这种路径出现了奇数次之类的就要想到异或(虽然确实也想到了)。

下一步特别神奇:对每种颜色赋一个随机权值,然后建一棵主席树,查询的时候在主席树上二分。

可能这种有关出现的问题都与随机权值有关吧……

关于主席树二分:首先肯定要在 \([l,r]\) 中异或和不为 \(0\),然后看 \([l,mid]\) 中异或和是否为 \(0\),如果不为零就递归下去找,否则就在 \([mid+1,r]\) 中寻找。

代码:https://pastebin.ubuntu.com/p/T7qy6dcc5v/

9.20

「ARC147D」Sets Scores(思维 + 结论)

「CF1363F」Rotating Substrings(神仙 dp)

题面

太神仙了吧……

无解显然就是组成 \(s\)\(t\) 的字符集合不同。

考虑操作的过程其实就是把一个字符往前面提任意个位置,那么我们就需要最小化移动的字符个数,即最大化不动的点的个数。

\(f_{i,j}\) 表示 \(s_{1\dots i}\)\(t_{1\dots j}\) 匹配的最小移动次数。注意到这里的匹配其实是在 \([i+1,n]\) 中再选一些数出来移动到前面使得它们匹配。

神奇的一步出现了:对于移动的字符的贡献的计算,我们考虑在它的原始位置计算。

转移:

  • 如果 \(s_i=t_j\),那么 \(f_{i,j}=f_{i-1,j-1}\)
  • 如果 \(s_i\) 移到前面去,那么就有 \(f_{i,j}=f_{i-1,j}+1\)
  • 如果是匹配了 \(t_{1\dots j-1}\) 之后,再从后面拿一个与 \(t_j\) 相同的字符到 \(i\) 之后,贡献是 \(f_{i,j}=f_{i,j-1}\),条件是 \([i+1,n]\)\(t_j\) 的字符数量要比 \([j+1,n]\)\(t_j\) 的字符数量多。

边界就是 \(f_{0,i}=0\),仔细想想发现其实是对的。

至于整个算法为什么是对的,题解里有一个比较好的解释。

代码:https://pastebin.ubuntu.com/p/4dvsC4QQ8T/

2022.9.20 考试 T1 T4

「CF1550E」Stringforces(二分 + 状压 dp)

题面

首先肯定是二分答案 \(mid\)

预处理出 \(nxt_{i,j}\) 表示在 \(i\) 后有连续 \(mid\) 个字符 \(j\) 的最近右端点,然后设 \(f_S\) 表示集合 \(S\) 中的字母已经满足条件的最近右端点,转移枚举当前最后一个满足的字母是 \(c\),然后 \(f_{S}\leftarrow\min(f_S,nxt_{f_{T}+1,c})\),其中 \(T\) 就是 \(S\) 去除 \(c\) 后的结果。

check 只需要判断 \(f_U\) 是否 \(\le n\)

代码:https://pastebin.ubuntu.com/p/3Bg9sVNwXC/

「UOJ592」新年的聚会(图上分治 + 结论)

题面

题意:

交互题。

有一张 \(n\) 个点 \(m\) 条边的图,你可以给定一个点集,询问该点集内的点之间有没有边。

你需要猜出这张图。

\(1 \le n \le 1000, 1 \le m \le 2000\)

询问次数 \(\le 50000 (O(m \log_2 n))\)

询问点集大小和 \(\le 10^6 (O(n\sqrt m))\)

$E's sol:

分治,求解一个点集之间的边前,我们将它分为两半,先求出两侧内部的边。

关键结论:对于一张 \(\bf{E}\) 条边的图,我们有办法将它的点集分为 \(\bf{O(\sqrt E)}\) 个独立集。

我们将两侧分别分割为独立集。然后对于两侧之间的一对独立集,再分治求解之间的边。

复杂度可以证明,询问次数 \(O(m\log_2 n)\),点集大小和 \(O(n\sqrt m)\)

于是我们可以先划分成若干个独立集,然后两两枚举独立集,求出它们之间的边。具体就是把较大的那个集合划分成两半,分别把较小的集合并进去,再去求边。

代码:https://pastebin.ubuntu.com/p/5ZRbcVS7k2/

其实主要还是那一个关键结论。证明可以考虑按照度数是否 \(\ge\sqrt m\) 来确定是单独划分一个独立集还是并到其它独立集里。

9.21

「CF1383E」Strange Operation(dp)

题面

不难发现题目的操作其实就是把序列分成若干段,然后把每一段都变成一个数,值是里面所有数的或。问改后的序列有几种情况。

首先,首尾的 0 都是可以单独考虑的,方案数为 \((cntL+1)(cntR+1)\),接下来我们只需要考虑中间的情况。

对于中间的数,一个 1 可以被删除当且仅当它的两端都有 1

把中间两个 1 之间连续 0 的个数抠出来变成一个序列,例如 \(s=\texttt{0010001101001010}\) 对应的序列就是 \(A=\{3,0,1,2,1\}\)

那么我们就相当于要找到能与原来的 \(A\) 序列匹配的 \(B\) 序列的个数,这里的“匹配”是指找到一个对应关系使得能将 \(A\) 序列划分成若干段,每一段都和 \(B\) 序列对应,段内最大值要 \(\ge\) \(B\) 序列里对应的值。

然后怎么想 dp 都会算重……自闭了。

感觉接下来的有点像 UOJ748 机器人表演,就是贪心匹配一个最早的位置。也就是设 \(f_i\) 表示匹配到 \(i\) 位置的方案数,那么如果这个位置上填 \(j\),从 \(k\) 位置转移过来就要满足 \([k+1,i-1]\) 中的 \(A\) 值都要 \(<j\),因为 \(i\) 值最早的匹配位置。所以只要记录填 \(j\) 之后前面最大的 \(A_k\ge j\),然后前缀和转移就行了。

代码:https://pastebin.ubuntu.com/p/rj2WRN9CBT/

「CF1539E」Game with Cards(二分 + ST 表 + dp)

题面

这种交换先后手的题目,可以考虑枚举在那个地方交换先后手,然后进行 dp(orz \(\text{\color{black}{C}\color{red}{XY07}}\))。

也就是设 \(dp_{i,0/1}\) 表示 \(i\) 这个位置填 \(0/1\) 是否可行,转移就枚举上一次交换在哪里,看这个区间是否满足条件。

举例来说,如果 \(i\) 要填 \(0\),那么前面就一定有一个 \(j\) 满足 \(dp_{j,1}=1\) 并且中间所有的 \(k\) 都在 A 的区间中、\(k_j\)\([j,i]\) 的 B 的区间中。前者可以记一个前缀和,后者可以提前二分 + ST 表预处理出来。填 \(1\) 类似。

具体的,dp 的时候需要动态维护,开一个 set 就行了。

代码:https://pastebin.ubuntu.com/p/kGSpMnmS45/

「CF1704D」Magical Array(性质 + 哈希)

题面

如果我们把权值设为 \(\sum ic_i\),那么操作一权值不变,操作二权值加一。算出所有数组的哈希值然后排序即可。

代码:https://pastebin.ubuntu.com/p/jrvrtjJnZ5/

「CF1704E」Count Seconds(暴力 + 拓扑排序)

题面

首先,直接拓扑是错的!因为有可能出现这个点被加权值之后不能立马出去。

究其原因还是有些点的权值为 \(0\)

因此我们可以先做 \(n\) 遍暴力,这样一个权值不为 \(0\) 的点的后继节点一定就都有权值了。

这个时候再跑拓扑排序就对了。

代码:https://pastebin.ubuntu.com/p/7bxqQ9pZhG/

「CF1539F」Strange Array(线段树)

题面

感觉还是比较套路的。

中位数的惯用套路,将 \(\le a_i\) 的权值设为 \(1\)\(>a_i\) 的权值设为 \(-1\)

感觉洛谷题解区(https://www.luogu.com.cn/problem/solution/CF1539F)里的图特别清楚,于是懒得写了

需要注意的是由于这个是上取整,所以当 \(i\)\(mid\) 右边的时候计算答案的 \(dis\) 时还需要 \(-1\)

代码:https://pastebin.ubuntu.com/p/vmQpF2rkGg/

9.22

「WC2016」论战捆竹竿 & 2022.9.22 考试 T3 高维入侵(利用 border 的性质优化同余最短路)

题面

首先可以暴力求出所有 \(\bf{border}\),然后暴力跑同余最短路。即使用 \(n-|\bf{border}|\) 能拼出多少个 \([n,m]\) 之间的数。

一个关键性质:所有 \(\bf{border}\) 形成了 \(\mathcal{O}(\log n)\) 个等差数列。

记录 \(f_i\) 表示在当前模数下要使得 \(\bmod mod=i\) 要加的最小数。

那么我们考虑依次加入等差数列。

剩下的懒得写了,见 https://www.luogu.com.cn/blog/PhantasmDragon/solution-p4156

代码:https://pastebin.ubuntu.com/p/GFv9JYrtX4/

2022.9.22 考试 T1 肃正协议(hash + 性质)

简要题意:给一个字符串,从左到右找出一些不交的子串,满足后一个包含前一个,问最多能找多少个。\(|S|\le 500000\)

我们将字符串 reverse 一下。首先发现如果每次只在左边或右边增加一个字符不会劣。第一个字符串长度一定为 \(1\),那么显然第 \(i\) 个字符串长度为 \(i\) 是最优的。

\(f_i\) 表示长度为 \(i\) 的前缀最多能选出多少个子串,显然 \(f_{i+1}\le f_i+1\)

注意到答案最多为 \(\mathcal{O}(\sqrt n)\),那么我们就可以把所有满足 \(i-j+1\le f_i\) 的哈希值插入一个 gp_hash_table 中,每次判断就只需要在其中查询答案即可。复杂度 \(\mathcal{O}(n\sqrt n)\)

常用防哈希冲突:随机权值!

代码:https://pastebin.ubuntu.com/p/YjQSVgqKwW/

9.23

「CF1614E」Divan and a Cottage(动态开点线段树)

题面

这都不会,退役罢!!1

显然答案随着温度的递增而不降。

考虑动态开点线段树,每个下标 \(i\) 维护初始值是 \(i\) 时的答案是多少。

每个节点维护区间内答案的 \(\max,\min\),加入一天时:

  • 若区间 \(\max<T\),区间 \(+1\)
  • 若区间 \(\min>T\),区间 \(-1\)
  • 若区间 \(\max=\min=T\),直接返回。
  • 否则递归左右区间。

不难发现这覆盖了所有情况。

代码:https://pastebin.ubuntu.com/p/KD4fPDyvyr/

9.24

「WC2010」重建计划(01 分数规划 + 点分治 + 单调队列)

题面

很明显可以用 01 分数规划的套路进行二分,然后每条边的权值减去一个数,求有没有长度在 \(L\sim U\) 之间的和为 \(0\) 的链。

对于路径问题肯定先考虑点分治,然后合并路径的时候可以单调队列。

因为卡常,所以需要把点分树提前建出来,不需要每次重新找重心。

代码:https://pastebin.ubuntu.com/p/DMrzvKFptY/

「CF1733E」Conveyor(递推)

题意:

给定一个 \(120 \times 120\) 的表格 \((0 − based)\),每个格子上有一个传送带,可以将史莱姆向右或向下传送一格,之后这个传送带的方向立刻发生变化,即向右变向下,向下变向右。

如果两个史莱姆撞上了,它们就会融合。如果一个史莱姆(向右或向下)走出了表格,那它确实就走出了表格。

初始的时候所有传送带们都向右,随后每一秒我们都在 \((0, 0)\) 放置一个新的史莱姆。

\(q\le 10^5\) 次询问,每次问在第 \(t(t \le 10^{18})\) 秒,\((x,y)\) 这个格子上是否有史莱姆。

首先,史莱姆肯定不会融合,因为每一个走过的距离都不一样。

那么我们可以考虑通过第 \(t\) 秒与第 \(t-1\) 秒时 \((x,y)\) 上的史莱姆个数是否相同来判断。

对于这个,可以递推:即先在 \(a_{0,0}\) 上放置 \(\max(0,t-x-y+1)\) 个史莱姆(因为在这之后放的都不可能到达 \((x,y)\)),\((i,j)\) 向右边会移动 \(\lceil\frac{a_{i,j}}{2}\rceil\) 个史莱姆,向下会移动 \(\lfloor\frac{a_{i,j}}{2}\rfloor\) 个。

代码:https://pastebin.ubuntu.com/p/337QRbS3v9/

「CF1612G」Max Sum Array(差分 + 贪心)

题面

如果位置 \(x\) 上放的是从前往后第 \(j\) 个值为 \(i\) 的数,那么它对答案的贡献就是 \((2j-c_i-1)x\)

很明显如果我们可以把所有的 \((2j-c_i-1)\) 拿出来然后从小到大排序依次填入,答案肯定是最大的。证明可以由排序不等式推出。

然而时间上不允许,所以我们可以考虑差分。一个 \(i\) 能贡献的范围是 \(1-c_i,3-c_i,\dots,c_i-3,c_i-1\),即一个公差为 \(2\) 的等差数列,放的时候就等差数列直接算和,因为它们的系数都是一样的。

求方案的话可以发现系数一样的可以随便排,就是 \(\prod cnt_j\)

注意开 LL!!!!

代码:https://pastebin.ubuntu.com/p/NnfF5xh7zp/

9.25

「ABC270G」Sequence in mod P(BSGS)

题面

把答案的式子写出来,其实就是要求满足 \(A^iS+A^{i-1}B+A^{i-2}B+\cdots+AB+B\equiv G\pmod P\) 的最小的 \(i\)

\(B=0\) 的时候就是 BSGS 模板,考虑在加入了 \(B\) 之后还是按照一样的套路,设阈值 \(M=\sqrt P\),然后预处理 \(0\sim M\) 的值存入哈希表,其它的暴力每次跳 \(M\) 的大小。

那么最后的式子也就形如:

\[(A^xS+A^{x-1}B+\cdots+AB+B)A^{y-x}+A^{y-x-1}B+A^{y-x-2}B+\cdots+AB+B\equiv G\pmod P \]

其中 \(x\) 是某个 \(M\) 的倍数。

移项后可得:

\[A^xS+A^{x-1}B+\cdots+AB+B\equiv G\times\frac{1}{A^{y-x}}-B\times(\frac{1}{A}+\cdots+\frac{1}{A^{y-x}}) \]

这样我们的思路就很明了了!

左右都可以递推得出来!

代码:https://pastebin.ubuntu.com/p/9Ctt5wdZZ4/

「洛谷 P8552」Rabbit(并查集 + 逆向思维)

题面

一个很显然的做法是,对于每一个点 \(x\),考虑它的子树,如果有 \(\ge 2\) 个儿子的子树内有没有被选过的点,那么就把它们和 \(x\) 标记上,并且答案 \(+1\),可惜这是 \(n^2\) 的。

考虑逆向思维,从小到大枚举点权,把一个点和它周围点权比它小的点全部并起来,记录一下每个连通块里还没有被匹配的点数。如果并完之后有 \(\ge 3\) 个未匹配的就匹配它们。

代码:https://pastebin.ubuntu.com/p/RbKt36SRT3/

「CF1527E」Partition Game(分治决策单调性 + 指针暴跳)

题面

直接暴力 dp 很显然,把式子写出来感性理解发现具有决策单调性。

分层转移的问题一般要长个心眼,想想有没有决策单调性。

莫队状指针移动可以考虑分治决策单调性!

然后套用 这里边 的分治决策单调性即可。

代码:https://pastebin.ubuntu.com/p/gkmkWFtp6v/

9.26

2022.9.26 考试 T1 T2

「CF1430G」Yet Another DAG Problem(状压 dp)

题面

很容易想到分层标号。

数据范围很小,考虑状压。

其实就差一步想到正解了……

关键一步:把连接层数不相邻的边的贡献拆到每一层里计算。

然后就可以很好地状压 dp 了。设 \(f_S\) 表示已经选了前面若干层的节点集合是 \(S\),那么可以枚举子集转移所有可能的下一层节点(条件是下一层节点的入点都在 \(S\) 中),贡献就是起点在 \(S\) 中、终点不在的所有边的权值之和。

方案也很好输出,记录每个状态从哪里转移过来即可。

代码:https://pastebin.ubuntu.com/p/PG4SYYvTTx/

「CF1611G」Robot and Candies(贪心 + set)

题面

神仙贪心.jpg

容易发现一次操作会使 \(x\leftarrow x+1\) 并且 \(x+y\leftarrow x+y\) 或者 \(x+y\leftarrow x+y+2\)。所以 \(x+y\) 的奇偶性不会发生变化,可以分奇偶考虑。

将所有 1 放到坐标系上考虑,其中 \(x\) 轴是行,\(y\) 轴是行 + 列,即原矩形中的 \(x+y\)

那么一次操作要么向右走 \(1\) 单位,要么向上走 \(2\) 单位且向右走 \(1\) 单位。

如果走出去了,我们就按边界对称过来。

重要结论:按照横坐标扫过去,如果这一行的后面还有点,就继续把这一行删完;否则将纵坐标 \(+2\) 继续操作。

证明可以考虑调整。

那么直接维护每一个纵坐标对应横坐标的集合 set,模拟这个过程就行了。

实现上注意我们只需要考虑有点的纵坐标。

代码:https://pastebin.ubuntu.com/p/p8GXCZ7B6p/

9.27

「CF1675G」Sorting Pancakes(DP)

题面

把问题放在前缀和序列上来考虑,手玩之后可以发现:操作一次就是其前缀和序列变化了 \(1\)

那么可以设 \(f_{i,j,k}\) 表示前 \(i\) 个数,最后一个数为 \(j\),和为 \(k\) 的最小操作次数。直接枚举下一个选什么就行,贡献为 \(|k+nxt-sum_{i+1}|\)

代码:https://pastebin.ubuntu.com/p/dJ86rM7MrV/

「CF1527D」MEX Tree(分类讨论 + 容斥)

题面

路径上的点的 \(\mathrm{MEX}=i\) 等价于有点 \(0\sim i-1\),并且没有点 \(i\)。我们可以直接处理出 \(ans_i\) 表示存在点 \(0\sim i\) 的路径条数。这个可以考虑以 \(0\) 为根,现在包含 \(0\sim i\) 的链的形状,即一端为 \(0\) 或者两端在 \(0\) 的两个不同的子树内,贡献可以直接计算。但是分类讨论有一点/tuu

容斥一下,\(ans_{i-1}-ans_i\) 就是 \(\mathrm{MEX}=i\) 的答案。

代码:https://pastebin.ubuntu.com/p/xTvjbxFDTX/

9.28

Hello 2020 A~D

「CF1523D」Love-Hate(随机化 + 高维后缀和)

题面

又一次败在了随机化的题上……

因为有不少于 \(\lceil\frac{n}{2}\rceil\) 个人在最终答案里,所以如果随机 \(i\) 个人,使得他在最终答案里,那么错误的概率将会是 \(\frac{1}{2^i}\)。所以问题转化为:一个人喜欢的货币中,最多选出多少个使得有不少于 \(\lceil\frac{n}{2}\rceil\) 个人都喜欢它们。

因为 \(1\le p\le 15\),所以可以考虑状压 DP。设 \(f_S\) 表示喜欢集合 \(S\) 中所有货币的人的数量,转移就是一个高维后缀和。求答案直接在 \(f_S\ge \lceil\frac{n}{2}\rceil\)\(S\) 中找 \(\rm{popcount}\) 最大的 \(S\) 就行了。

感觉这种随机化基本想不到啊……还是要多见见。

代码:https://pastebin.ubuntu.com/p/cxKvrx53ws/

2022.9.27 联考 T4

「CF1523E」Crypto Lights(期望转概率 + 组合数学)

题面

\(p_i\) 为最终开了 \(i\) 盏灯的概率,那么 \(E=\sum\limits_{i=1}^n p_ii\)

直接求并不好求,我们考虑化一下式子:\(E=\sum\limits_{i=1}^n\sum\limits_{j=i}^n p_j\),这样如果设 \(s_i=\sum\limits_{j=i}^n p_j\),那么 \(E=\sum\limits_{i=1}^n s_i\)

考虑 \(s_i\) 的意义,是最终开了 \(\ge i\) 盏灯,那么就相当于前面 \(i-1\) 盏灯没有冲突。这个很好求,相邻两盏灯之间的间隔都要 \(>k-1\),所以方案数就是 \(\binom{n-(k-1)(i-1)}{i}\),概率就还需要除一个 \(\binom{n}{i}\)

那么就做完了!

代码:https://pastebin.ubuntu.com/p/yfbDrjMWR3/

「洛谷 P5574」[CmdOI2019]任务分配问题(分治决策单调性优化 DP + 莫队状指针移动)

题面

很明显的暴力 dp:设 \(f_{i,j}\) 表示前 \(i\) 个数分成了 \(j\) 段的最小无序度之和。转移可以枚举上一段的起点在哪里。

对于划分区间的问题,需要长个心眼:是否满足决策单调性(四边形不等式),即 交叉 \(\le\) 包含?

发现这道题中确实如此,证明可以考虑讨论一下 一个产生贡献的点对中 的 两个点 在大区间中的位置。此处略去。

那么就可以愉快地跑分治决策单调性了!指针的移动可以像莫队那样子做(注意初始化 \(L=1\)),复杂度可以证明是正确的。

代码:https://pastebin.ubuntu.com/p/HWNwYYBTjt/

9.29

「CF1499F」Diameter Cuts(树形 DP)

题面

直径可以 DP 求,那么和直径相关的量也应该想到 DP。

\(f_{u,i}\) 表示 \(u\) 子树内连接 \(u\) 的最长链是 \(i\),且满足条件的方案数。

转移时枚举每条边 \((u,v)(v\text{\ is a son of } u)\) 是否断开:

  • 若断开,则 \(f_{u,i}\leftarrow f_{u,i}\times\sum\limits_{j=0}^k f_{v,j}\)
  • 若不断开,那么 \(f_{u,\max(i,j+1)}\leftarrow f_{u,i}\times f_{v,j}(i+j+1\le k)\)

答案即为 \(\sum\limits_{i=0}^k f_{1,i}\)

代码:https://pastebin.ubuntu.com/p/y4t6yVp8hB/

「CF1499E」Chaotic Merge(DP)

题面

\(f_{i,j,0/1}\) 表示 \(x\) 匹配到第 \(i\) 位,\(y\) 匹配到第 \(j\) 位,最后一位是 \(x_i/y_j\) 的方案数。

转移可以直接看倒数第二位是什么。

注意新开一个串的情况需要单独讨论,需要从 \(f_{0,j,1}/f_{i,0,0}\) 转移过来,而这些需要预处理。

代码:https://pastebin.ubuntu.com/p/QRBTGXnxBd/

「CF1572B」Xor of 3(构造)

题面

容易发现操作不会改变整个序列的异或和,所以如果有解,那么原序列异或和一定为 \(0\)

考虑如果 \(n\) 是奇数,那么可以先操作 \(n-2,n-4,\dots,3,1\) 来使得 \(a_n=a_{n-1},a_{n-2}=a_{n-3},\dots,a_3=a_2,a_1=0\),然后再反过来操作就可以得到全 \(0\)

如果 \(n\) 是偶数,那么找一个异或和为 \(0\) 的长度为奇数的前缀,前后分别来做 \(n\) 是奇数的构造就可以了。

代码:https://pastebin.ubuntu.com/p/SyrPsNwWbG/

「CF1585F / CF1571F」 Non-equal Neighbours & 「ARC115E」LEQ and NEQ(容斥 + 单调栈优化线性 DP)

题面

首先考虑容斥一下,假设有若干个 \(b_i=b_{i+1}\),那么就相当于把序列分成了一堆相等的段,段与段之间不一定不同。

那么答案就是 有 \(n\) 段的答案 \(-\)\((n-1)\) 段的答案 \(+\)\((n-2)\) 段的答案 \(\cdots\pm\)\(1\) 段的答案 \(\mp\)\(0\) 段的答案。

其实这个东西等价于:

  • \(n\) 是奇数时,答案为 分成奇数段的 \(-\) 分成偶数段的;
  • \(n\) 是偶数时,答案为 分成偶数段的 \(-\) 分成奇数段的。

那么可以考虑设 \(f_{i,0/1}\) 表示填完了 \([1,i]\),分成了偶数段 / 奇数段的答案。

转移:\(f_{i,0/1}=\sum\limits_{j=0}^{i-1}f_{j,1/0}\times\min\limits_{k=j+1}^i\{a_k\}\)

暴力做是 \(\mathcal{O}(n^2)\) 的。

看到这种区间 \(\min\) 的转移形式,需要联想到单调栈。维护一个严格递增的单调栈,那么设 \(x\)\(i\) 左边第一个小于 \(a_i\) 的位置,则有 \(f_{i,0/1}=f_{x,0/1}+a_i\times\sum\limits_{j=x}^{i-1}f_{j,1/0}\)。因为对于 \(1\sim x-1\) 的所有 \(y\) 转移到 \(i\) 的贡献为 \([y+1,i]\) 中的 \(\min\),这和 \([y+1,x]\) 中的 \(\min\) 一样,即贡献一样。所有这些贡献全部转移到了 \(f_{x,0/1}\),所以可以直接继承过来。

那么只需要维护一下分成 偶数段 / 奇数段 的前缀和就行了。

代码:https://pastebin.ubuntu.com/p/bGYQJvMgjd/

「CF1578L」Labyrinth(Kruskal 重构树 + 结论)

题面

首先肯定是建出最大生成树。

然后考虑,如果当前身体宽度比某些边大,那么这些边其实可以被理解为已经断掉了。

那么有一个结论:一条边如果断掉了,那么它的子树内的糖果一定已经全部被吃过了。证明显然。

于是就可以在建树的时候递推答案,在 先左子树后右子树 和 先右子树后左子树 中的答案取 \(\max\),这个“答案”其实就是 需要走完一个子树的最大初始身体宽度和当前边权取 \(\min\) 后减去还没走的子树内的糖果数量。

具体可以见代码理解。

代码:https://pastebin.ubuntu.com/p/nD7bZQfQ4M/

9.30

「CF1497E2」Square-free division (hard version)(转换枚举量 + 双指针 + DP)

题面

首先可以把每个数的平方因子除掉,很明显这样对答案没有影响。

\(f_{i,j}\) 表示前 \(i\) 个修改 \(j\) 次最多分了几段,转移的时候需要一个辅助数组 \(mx_{i,j}\) 表示以 \(i\) 结尾,修改 \(j\) 次能到达的满足条件的最远端点,那么 \(f_{i,j}\leftarrow\min\limits_{l=0}^j\{f_{mx_{i,l}-1,j-l}+1\}\)

考虑怎么求这个 \(mx_{i,j}\)。一个性质是在 \(j\) 不变的情况下,\(mx_{i,j}\) 随着 \(i\) 的递增而不降。那么就可以通过双指针来求。

注意有点卡常,需要预处理出每个数去掉平方因子后的结果。

代码:https://pastebin.ubuntu.com/p/ZgZzp8tHdT/

posted @ 2022-08-30 21:07  csxsi  阅读(18)  评论(0)    收藏  举报