随机乱做 Part 4

「CF1739E」Cleaning Robot(DP)

题面

题意:

给定一张 \(2\times n\) 的网格,有一些格子是脏的。有一个扫地机器人每次都会选择曼哈顿距离最近的一个格子清理,如果有多个距离最近的就会发生故障。现在你需要先清理一些脏的格子使得机器人不会故障,问最多能保留多少脏的格子。

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

首先可以预处理出来 \(nxt_{i,j}\) 表示和 \((i,j)\) 同一行的后一个脏格子,如果没有就是 \(+\infty\)

然后考虑设计一个 dp:设 \(f_{i,j,k}\) 表示机器人现在在 \((i,j)\)\(1\sim j-1\) 列的格子已经全部被清理,上一次清理的在 / 不在第 \(i\) 行,能保留的最多脏格子。

转移的时候考虑两种情况:

  • \(k=0\),那么第 \(i\) 行的下一个格子一定会在 \((i,j+1)\) 之后,第 \(i\oplus 1\) 行的下一个格子一定会在 \((i,j)\) 之后。
  • \(k=1\),我们肯定不能选 \((i\oplus1,j+1)\),然后贪心地选择 \((i,j+1)\)(因为距离 \((i,j)\)\(1\) 的合法格子只有这个),下一个就在 \((i\oplus1,j+2)\)\((i,j+2)\) 之后选择。

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

「CF1738E」Balance Addicts(双指针 + 组合计数)

题面

题意:

定义一个长度为 \(len\) 的序列 \(\{a_{1...len}\}\)平衡的 当且仅当 \(\forall 1\le i\le len,a_i=a_{len-i+1}\)

给定一个长为 \(n\) 的序列 \(a_{1...n}\),求把它划分成若干个子段,每个子段的和拼接而成的序列是 平衡的 的方案数。

数据范围:\(1\le n\le 10^5,1\le a_i\le 10^9\)

\(f_{l,r}\) 为区间 \([l,r]\) 满足条件的方案数。

考虑分情况讨论:

  • 如果区间内全是 \(0\),那么 \(f_{l,r}=2^{r-l}\)
  • 如果 \(a_l=a_r=0\),设 \(x\) 为前缀 \(0\) 的个数,\(y\) 为后缀 \(0\) 的个数,那么 \(f_{l,r}=f_{l+x,r-y}\times\sum\limits_{i=0}^{\min(x,y)}\binom{x}{i}\binom{y}{i}\),由范德蒙德卷积可知 \(f_{l,r}=f_{l+x,r-y}\times\binom{x+y}{x}\)
  • 否则,求出一个最小的 \(L\) 和最大的 \(R\) 满足 \(a_l+a_{l+1}+\cdots+a_L=a_R+a_{R+1}+\cdots+a_r\)
    • 如果找不到,那么 \(f_{l,r}=1\)
    • 如果 \([L+1,R-1]\) 中全都是 \(0\),那么 \(f_{l,r}=2^{R-L}\)
    • \(c0\)\([L+1,R-1]\) 中前缀 \(0\) 的个数,\(c1\) 为后缀 \(0\) 的个数,那么 \(f_{l,r}=f_{L+c0,R-c1}\times\sum\limits_{i=0}^{\min(c0+1,c1+1)}\binom{c0+1}{i}\binom{c1+1}{i}=f_{L+c0,R-c1}\times\binom{c0+c1+2}{c0+1}\)

其实画画图,多举几个例子应该都可以理解。

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

「CF1738F」Connectivity Addicts(交互 + 贪心 + BFS)

题面

题意:

这是一道交互题。

有一张 \(n\) 个点的无向简单图,你只知道每个点的度数,要求给图上的每个点染色,满足:

  • 每种颜色形成一个连通块;
  • \(s_c\) 为颜色为 \(c\) 的所有点的度数之和,\(n_c\) 为颜色为 \(c\) 的点的个数,那么 \(s_c\le n_c^2\)

每次询问你可以选择一个节点 \(u\),然后你可以得到与 \(u\) 相连的第 \(k\) 个节点(即 \(u\) 连接的第 \(k\) 条边的另一个端点),其中第 \(i\) 次询问点 \(u\) 时的 \(k=i\)

你需要使用不超过 \(n\) 次询问来解决这个图染色问题。

数据范围:数据组数 \(T\le 1000,1\le n\le 1000,0\le deg_i\le n-1\)

神仙题。

考虑将点按照度数从大到小排序,每次取出还未被染色的度数最大的点 \(u\),进行如下流程:

  • 维护一个点集 \(S\)。一开始 \(S=\{u\}\)
  • 扫描 \(u\) 的连边 \((u,v)\)
    • 如果 \(v\) 已经有颜色,那么将点集 \(S\) 中的点全部染成 \(col_v\)。并且结束当前 BFS。
    • 否则就将 \(v\) 加入点集 \(S\)
  • 如果当前过程未结束,就将 \(S\) 中的点全部染成一种新的颜色。

首先,连通的条件肯定是满足的。

其次,因为我们按照度数递减的顺序枚举点,所以就有 \(\max\limits_{col_u=c}\{deg_u\}\le n_c\),进而有 \(deg_u\le n_{col_u}\)

然后考虑另一个限制条件:

  • 如果 \(u\) 相邻的节点全部没有被访问,那么 \(s_c=\sum deg\le deg_u\times(deg_u+1)\le (deg_u+1)^2=n_c^2\)
  • 否则,可以使用归纳法。设 \(s_c'\)\(v\) 所在颜色的度数之和, \(n_c'\)\(v\) 所在颜色的点数。那么肯定有:
    • \(s_c'\le (n_c')^2\)。归纳法的条件。
    • \(d_u\le d_v\le n_c'\)。前面已经提到过。
    • \(s_c=s_c'+\sum deg\le s_c'+d_v\times cnt\le (n_c')^2+n'c\times cnt\le (n_c'+cnt)^2=n_c^2\)

所以,我们就证明了这个做法的正确性。

代码:https://pastebin.ubuntu.com/p/898tp8MQGw/

「SCOI2007」k 短路(二分 + 暴力 Dijkstra + 搜索)

题面

首先可以考虑二分路径的长度 \(mid\),那么我们现在就只关心长度 \(\le mid\) 的路径。

从起点开始拓展路径,保证每次都可以拓展出合法的路径。具体的,不考虑已经走过的点,如果当前路径接上当前点到终点的最短路距离仍然比 \(mid\) 大,那么就不考虑这条路径(即剪枝)。这个可以在搜索的时候使用暴力的 \(\mathcal{O}(n^2)\) Dijkstra 计算。

每次都可以 dfs 出一条合法的路径,每条路径对复杂度的贡献是 \(\mathcal{O}(n^3)\)(因为每个点都会跑一次 \(\mathcal{O}(n^2)\) 的 Dijkstra)。那么总复杂度就是 \(\mathcal{O}(n^3k\log w)\)

注意输出路径的时候,要把长度 \(\le mid-1\) 的路径先去掉,因为统计的是 \(\le mid\) 的路径数量。

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

「CF1450E」Capitalism(最短路应用 + 差分约束)

题面

首先可以把条件转化为 \(1\le a_j-a_i\le 1\)\(-1\le a_j-a_i\le 1\)。然而我们忽略了 \(a_j=a_i\) 的情况,这个时候它也是不合法的。

看到绝对值 \(=1\),其实可以想到建图之后应该是一个二分图。否则就会出现奇环,肯定有两个数绝对值相等,不合法。所以直接把有奇环的情况判掉就行了。

然后就可以直接跑差分约束了。如果差分约束无解那么题目肯定无解。

否则,我们考虑固定最小值,找它到所有点的距离的最大值,在所有这种 \(\max-\min\) 的形式中找到极差最大的。

容易发现极差最大的解中每个数(即距离)一定都是非负的。证明考虑调整。

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

「CF1730E」Maximums and Minimums(并查集 + 单调栈)

题面

题意:

给定一个长度为 \(n\) 的序列 \(a_1,a_2,\dots,a_n\),问有多少个区间满足区间 \(\max\) 是区间 \(\min\) 的倍数。

数据范围:数据组数 \(t\le 10,\sum n\le 5\times10^5,1\le a_i\le 10^6\)

一开始想了个最值分治 + 二分,有点难写/tuu

实际上有一种巧妙的做法。

先用单调栈求出每个数左边第一个 \(\ge\) 它的数的位置和右边第一个 \(>\) 它的数的位置,这个很方便。

然后考虑从大到小枚举最小值,然后枚举这个最小值的倍数作为最大值。那么我们就是要计算出同时包含最小值和最大值的区间个数。

可以使用容斥,即用 最大值确定合法、最小值大于等于要求的值 的区间数量减去 最大值合法、最小值大于要求的值 的区间数量。

这个可以使用并查集维护区间信息。具体的,每次加入一个数的时候就将它向左右合并,表示这个数已经可以被考虑进贡献中。

可能还是有点没讲清……看代码应该可以理解。

代码:https://pastebin.ubuntu.com/p/96WJqXXyGc/

「AGC013D」Piling Up(DP + 容斥)

题面

首先有一个显而易见的 DP:设 \(f_{i,j}\) 表示已经进行了 \(i\) 次操作,还剩下 \(j\) 个黑球的颜色序列数。转移的时候由于球的总数不变,所以只需要关心黑球 / 白球的有无,讨论四种情况即可。

但是这样会导致算重,因为相同的颜色序列一开始可能会有不同的黑球数。

那么考虑去重,我们只统计途中黑球的最小值刚好为 \(0\) 的那一次操作序列。

可以在 dp 式子里再加一维,同时也可以直接用有 \(n\) 的球的答案减去有 \(n-1\) 个球的答案。

为什么呢?这是因为如果途中黑球最小值不是 \(0\),那么把一开始的黑球数减去 \(1\) 该方案仍然可行。所以所有中间算重的操作序列最后都会被减掉,只会留下一个。

代码很好写:https://pastebin.ubuntu.com/p/DfWjCQ6YNp/

CODE FESTIVAL 2016 Final H - Tokaido(deque + 整体 DP)

题面

\(f_i\) 表示当前操作者在 \(i\) 位置,对手在 \(i+1\) 位置时二者最大的分差(当前操作者的分值 - 对手的分值)。

那么当前的操作肯定是在 \(i+1\) 后面选一个位置 \(j\),然后对手把 \([i+1,j-1]\) 全部选掉,即:

\[\begin{aligned} f_i&=\max\limits_{j>i+1}\{a_j-(s_{j-1}-s_i)-f_{j-1}\}\\ &=s_i+\max\limits_{j>i+1}\{a_j-s_{j-1}-f_{j-1}\} \end{aligned} \]

其中 \(s_i=\sum\limits_{j=1}^i a_j\)

记录后缀 \(\max\) 就可以单次询问做到线性。

进一步拆式子。把 \(f_{i+1}\) 带进去,化简可以惊奇地发现 \(f_i=|a_{i+1}-f_{i+1}|\)

那么考虑整体 DP。设 \(g_{i,j}\) 表示以 \(j\) 为初始值,从 \(i\) 开始往前扫得到的最终值。转移形如 \(g_{i,j}=g_{i+1,|a_i-j|}\)

很显然,这个 DP 的形式大概就是把 DP 数组向右移 \(a_i\) 位,然后再把原先的 \(g_{1\dots a_i}\) 翻转一下插到前面(打一个表也可以发现)。可以用一个 deque 来维护。

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

「CF685E」Travelling Through the Snow Queen's Kingdom(Floyd + 倒序加边)

题面

题意其实应该是:如果在 \(\le i\) 的时刻经过第 \(i\) 条边,那么走出第 \(i\) 条边的时间就是 \(i\) 时刻。

考虑倒过来加边,记录 \(f_{i,j}\) 表示从 \(i\)\(j\) 经过的最大边权最小是多少。那么加入这条边 \((u,v)\) 之后影响的 \(f_{i,j}\) 一定满足 \(i=u/i=v/j=u/j=v\),更新可以做到一次 \(\mathcal{O}(n)\)

那么把询问离线,挂在 \(l\) 位置上,可以直接判断能否走到。

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

「CF1707E」Replace(ST 表 + 倍增)

题面

考虑倍增,设 \(f_{i,j,k}\) 表示 \([i,i+2^j-1]\)\(2^k\) 步所得到的区间的左端点,\(g_{i,j,k}\) 为对应的右端点。

首先可以预处理出所有 \(f_{i,j,0}\)\(g_{i,j,0}\),这就是一个区间最值。

然后,发现区间是可合并的,那么就都可以 ST 表预处理出来。

注意 cache miss 和答案上界(其实是比 \(n\) 大的)!!!!!

关键还是在于发现可合并性。

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

posted @ 2022-10-10 21:07  csxsi  阅读(33)  评论(0编辑  收藏  举报