省选计划(第二周)

知识回顾:

  • 巩固:二分,倍增,优化DP,莫队,分数规划,网络流,二分图,贪心,set/map,KMP

  • 深入研究:分治(线段树分治),后缀数组,费用流

  • 简单了解/没学明白:线性基,边分治,数位DP,博弈论

练题:

[SCOI2015]国旗计划

直接模拟复杂度 \(O(n^2)\),显然会超时,于是考虑倍增。

定义 \(st_{i,j}\) 表示从 i 这条线段走 \(2^j\) 次所能到达的最远的线段编号。

转移显然,\(st_{i,j}=st_{st{i,j-1},j-1}\)

为了方便,可以断环为链。

复杂度 \(O(n \log n)\)

Yet Another Minimization Problem

神仙题。

第一眼看上去就是 DP。

定义 \(f_{i,j}\) 表示当前点 i,分 j 段的最小费用。

\(f_{i,j}= min(f_{i,j},f_{k,j-1}+val_{k+1,i})\)

然后发现复杂度 \(O(n^2k)\),直接 T 飞,需要优化。

我们发现 j 那一维可以滚掉,也就是只考虑第一维,然后做 j 次就行了,下面称 \(f_{i,j}\)\(f_i\)

对于 \(val_{i,j}\),我们发现当 j 固定时,i 越小,值越大 (废话。

接下来最关键的一步就是证明转移的最优决策点是单调不降的。

我们考虑反证法。

定义 u 为当前点 i 的最优决策点,v 为 i+1 的最优决策点。

那么 \(f_u+val(u+1,i) \le f_v+val(v+1,i)\)

若 v < u,则对于 i+1 应当满足:\(f_v+val(v+1,i+1) \le f_u+val(u+1,i+1)\)

即:\(f_v+val(v+1,i)+ \Delta v \le f_u+val(u+1,i)+ \Delta u\)

根据之前发现的单调性,显然可以得出 \(\Delta v \ge \Delta u\),即 \(\Delta v-\Delta u \ge 0\)

所以移项可得 \(f_u+val(u+1,i) \ge f_v+val(v+1,i)+(\Delta v-\Delta u)\),与前者矛盾,证毕。

接下来就可以用分治来优化了。

定义 \(cal(l,r,L,R)\) 为当前处理的区间 \([l,r]\) 和可能的最优决策点所在区间 \([L,R]\)

对于一个这样的函数,我们可以暴力找到 \(mid=\left\lfloor l+r \right\rfloor\) 的最优决策点 p, 然后递归下去。

那么问题来了,怎么快速求出 \(val(l,r)\) 呢?直接莫队就行了!

复杂度 \(O(kn \log n+n \sqrt n)\)

P4322 [JSOI2016]最佳团体

分数规划+树形背包。

可以根据推荐关系建出一颗树,然后如果选了一点,则该点到根上的所有点都必须选。

二分 mid,定义每个结点的权值,然后判断选 k+1 个节点的最大值是否大于 0。

\(f_{i,j}\) 为当前节点 i,在其子树内选了 j 个节点,最大点权和为多少。

转移方程为 \(f_{u,j}=max(f_{u,j},f_{u,j-t}+f_{v,t})\)

初始化为 \(f_{u,0}=0\)\(f_{u,1}=val_u\),其余皆为 -inf。

然后我们发现这个 DP 的复杂度貌似是 \(O(n^3)\)

但将各种限制条件加上后就变成了 \(O(n^2)\)。本人很菜,没法证明。

所以最终复杂度为 \(O(n^2 \log n)\)

P3705 [SDOI2017]新生舞会

求比值,分数规划。

对于每一个男生向所有女生连一条容量为 1,费用为 \(a_{i,j}-c \cdot b_{i,j}\) 的边,原点 s 向所有男生连一条容量为 1,费用为 0 的边,所有女生向汇点 t 也连一条容量为 1,费用为 0 的边。

然后跑一边 KM 或者最大费用最小流就行了。

复杂度 \(O(玄学)\)

A Museum Robbery

线段树分治。

我么发现添加物品容易,而删除物品难。

考虑把物品出现和删除的时间点表现在数轴上,那么一个物品的贡献就在这个区间内。

假设一共有 cnt 个查询操作,则我们建一棵大小为 cnt 的线段树。

然后对于每一个物品,将其区间拍在线段树上。

为了方便操作,可以在每个线段树结点上开一个 vector 存储被哪些物品覆盖。由于一个物品只会体现在 log 个结点上,所以 vector 的总空间为 \(O(q \log q)\),不用担心 MLE。

最后遍历整棵线段树,对当前结点 vector 内的元素背包,然后再将 DP 数组下传给左右儿子。

最后每个叶子节点都对应一个询问,直接输出就行了。

复杂度 \(O(nk+q \log q)\)

P5787 二分图 /【模板】线段树分治

模板题。

线段树分治还是该咋写咋写,二分图的判断需要注意一下。

常见的方法是黑白染色,但这里不行,要用拓展域并查集。

也就是把一个点 u 拆成 u 和 u+n 两个点,每次连边只连两个不同域内的点,如果发现 u 和 u+n 在一个集合里,则说明有奇环,不是二分图。

线段树分治返回的时候,并查集显然也要返回初始状态,所以不能进行路径压缩,为了使复杂度有保证,改用安秩合并。

撤回时可以借助栈。

复杂度 \(O(n \log n \log n)\)

Painting Edges

可以说是模板题的进阶吧。

首先并查集要变成 k 个,对于每一种颜色都维护一下。

考虑一条边被染成某种颜色所处的时间段为 \([x,y]\),那么会有两种情况。

1.染上去了,更新颜色。

2.没染上去,还是之前的颜色。

最后跑一边 dfs 就行了。

复杂度 \(O(m \log n \log q)\)

Painting Edges

还是线段树分治。

每次给一条边,如果没有就添加,如果存在就删除。

于是可以转化成一段存在的区间,可借助 map 记录是否存在。

剩下的就是板子了。

复杂度 \(O(n \log n \log n)\)

[ABC281E] Least Elements

考场代码写得就是一坨屎,最后弃了。

我们可以定义一个 multiset 来存当前 m 个数。

添加元素:如果插入后在前 k 小,则减去第 k 个,加上这个数,否则不进行任何操作。

删除元素:如果要删除的元素在前 k 小,则减去这个数,加上第 k+1 个数,否则不进行任何操作。

复杂度 \(O(n \log n)\)

[ABC281F] Xor Minimization

题目要求我们求这个式子:

\[\min_{i=0}^{\infty}\max_{j=1}^{n}a_j \oplus i \]

可以从高到低考虑每一位。

如果当前这些数的第 k 位都相同,则可以忽略这一位。

否则的话可以将这些数分成两类,一类为 0,一类为 1,然后递归处理。

复杂度 \(O(n \log n)\)

CF1442D Sum

背包+分治。

最朴素的做法是分组背包,对于每一个数组,考虑其每一个前缀,复杂度 \(O(nk^2)\)

然后我们发现这些数组有着很好的性质,那就是不降。

于是就可以推出最佳的选法一定是全选若干个再加上一个选一些的,证明如下。

假设有两个数组都选了一部分数,其最后一个数分别为 a 和 b,且 a > b。

则显然在 a 后面继续选会更优。

接下来考虑分治。

对于当前区间 \([l,r]\) 计算出 mid,将 \([mid+1,r]\) 做一遍 01 背包,然后递归 \([l,mid]\)

同理 \([mid+1,r]\) 也需要递归一遍。

如果 \(l==r\),那么枚举一下数组 l 选的长度,更新一下就好了。

最后输出最大值。

复杂度 \(O(nk \log n)\)

Compress Words

KMP简单题。

对于两个字符串a、b,我们要求出最大的 i 使得 \([lena-i,lena-1]\)\([0,i-1]\) 相等。

然后可以把 b 接在 a 前面,中间隔上一个 \(#\),跑一边 KMP 求出 border,然后去掉公共部分把 b 拼上就行了。

复杂度 \(O(n)\)

【模板】后缀排序

很久以前就学过,但没太学懂,经过董老师的一番讲解,我豁(geng)然(jia)开(meng)朗(bi)。

定义 \(sa_i\) 为 s 的所有后缀中字典序第 i 小的编号。

\(rk_i\) 为后缀 i 的排名。

两者间关系为:\(rk[sa[i]]=sa[rk[i]]=i\)

可以用倍增求解。

任何长 \(2^k\) 的子串都可以表示成两个长为 \(2^{k-1}\) 的子串的拼接。

若知道所有长 \(2^{k-1}\) 的子串的排名,则长 \(2^k\) 的子串可以用一个二元组表示。

假如我们用 sort 进行排序,复杂度为 \(O(n \log n \log n)\),不太 nice。

所以考虑用基数排序优化掉一个 log,即先对第二个排序,再对第一个排序。

P2408 不同子串个数

求出 height 数组,然后用总方案数减去所有 height 数组之和,即:

\[\frac{n(n+1)}{2}-\sum\limits_{i=1}^{n}height_i \]

P2045 方格取数加强版

费用流题。

先拆点,分成入点和出点。

对于每一个点 \((i,j)\),从入点向出点连一条容量为 1,费用为 \(c_{i,j}\) 的边,和一条容量为 k-1,费用为 0 的边。

然后 \((i,j)\)\((i,j+1)\) 连一条容量为 k,费用为 0 的边,\((i,j)\)\((i+1,j)\) 也连一条容量为 k,费用为 0 的边。

最后跑一边最大费用最大流就行了。

P4452 [国家集训队]航班安排

很麻烦的费用流。

我们可以给订单拆点,容量为 inf,费用为该订单的收益。

然后给起点 1 也拆一下,容量为 k,费用为 0。

如果起点到某个订单的起点的时间符合要求,则连一条容量为 inf,费用为 \(-f_{s, x[i].a}\)

如果某个订单能按时回到起点 1,则连一条容量为 inf,费用为 \(-f_{x[i].b,t}\)

接着两两枚举订单,如果订单 i 能按时到达订单 j,则连一条容量为 inf,费用为 \(-f_{x[i].b, x[j].a}\)

最后跑一边费用流。

模拟赛:

USACO

AK了铜组,银组差十秒AK(可恶。

一周过后终于出结果了,没晋级......

铜组:

[USACO22DEC] Cow College B

排序,对于每个值算一下就好了,比较简单。

复杂度 \(O(n \log n)\)

[USACO22DEC] Feeding the Cows B

神奇的贪心。

首先我们可以把一块草的贡献理解为一个 \([i-k,i+k]\) 的区间,然后可以从左到右枚举每一头牛。

如果当前牛被区间覆盖,忽略。

否则的话以这头牛为左端点安排一个区间。

需要注意的是如果 \(i+k>n\),那么可以先忽略这头牛,都处理完后从后往前找到第一个空位安排一下就行了(直观感受是对的,但我不会证明......

复杂度 \(O(n)\)

P8899 [USACO22DEC] Reverse Engineering B

有意思的题。

判断有没有说谎其实就是看能否构造出可行解。

可以发现,if/else if/else 的组合的实际意义是每次根据某位的特性删去一部分字符串,而能够删除的条件是:当前拥有这个特性的所有字符串所返回的值相同。

接下来就好办了,我们采用贪心的策略。

如果当前位能够排除一波,那就执行一下。

为什么要立刻执行呢?因为如果一位能排除,那么不管怎么删除字符串都不会对其造成影响,反之的话就有可能使其成立。

所以这样的贪心是正确的。

复杂度 \((n^3)\)

银组:

P8900 [USACO22DEC] Barn Tree S

第一眼看上去没什么思路。

考虑以 1 为根,计算其所有子树内干草的数量,然后可以判断出从节点 u 和它的父亲之间需要运多少草。假如需要从 u 向 \(fa_u\) 运 w 捆草,那么连一条 \((u,fa_u,w)\)

可以发现这是一个 DAG,于是跑一边拓扑排序就行了。

复杂度 \(O(n)\)

P8901 [USACO22DEC] Circular Barn S

考场上因为一些小细节没调出来!!!

定义 \(f_i\) 表示有 i 头牛,先手能否赢。

定义 \(g_i\) 表示有 i 头牛,如果双方都采取最优策略,需要多少次结束。

先用埃氏筛找出所有质数,然后对于递推求出 f 和 g。

如果存在 j,使得 \(j==i-prime\)\(f_j==0\),则 \(f_i=1\),否则 \(f_i=0\)

如果 \(f_i==0\),则 \(g_i=\max\limits_{k=1}^{num}g_{i-prime_k}+1\)

否则 \(g_i=\min\limits_{k=1}^{num}g_{i-prime_k}+1\)

然后发现 T 飞了。

但是我们通过打表发现,如果 \(4 \ |\ i\),则 \(f_i=0\),否则 \(f_i=1\)。对于所有偶数,\(f_i=\frac{i}{2}\)

于是只需要考虑 i 为奇数的情况。

因为所有奇数的 i 都有 \(f_i=1\),而满足 \(f_j=0\) 的 j 必为 4 的倍数且 \(g_j\) 具有单调性,所以我们可以从大到小枚举质数,找到第一个满足 \(4 \ | \ i-prime_k\) 的 k,令 \(g_i=g_{i-prime_k}\)

最后判断输赢的时候只需要对于每一个数找到 \(\frac{g_{val_i}}{2}\) 最小且最靠前的 i,并判断 \(f_{val_i}\) 即可。

复杂度很玄学,但是能过。

P8902 [USACO22DEC] Range Reconstruction S

别看题面很唬人,其实是个诈骗题。

我们知道相邻点的差的绝对值 r。如果 \(2^n\) 枚举显然不行。

假如我们有三个数,后两个的值不同且已经确定了(如果相同的话就可以合并成 1 个点),可以发现第一个数的值是唯一确定的。

于是我们就可以从后往前构造。

\(a_n=0\),然后对于每一位的两种情况都分别试一下,取满足的一种就行了。

复杂度 \(O(n^2)\)

A计划

太难了,打完部分分跑路了。

最终得分 20+20+40=80 rk15

贴一下官方题解。

T300672 A

对于每一个\(i\),考虑给每条边一个定向,如果\(u\to v\),那么另\(p_u=p_v+w\),否则\(p_v=p_u+w\)

那么如果一条路径上边的方向都是从\(u \to v\)或者\(v \to u\)\(|p_u-p_v|=dis(u,v)\),否则\(dis(u,v)\leq |p_u-p_v|\)

考虑边分治,每次左边的所有边指向根节点,右边的所有边从根指向儿子即可。

或者点分治,每一层套一个二进制分组。二进制位为\(1\)的从下往上指,否则从上往下指。

ps:由于点分治不熟,不订正了。

T300674 B

显然,可以把两个数都填满前导零,答案也不会变。

最好的方法就是把\(x\)按位排序,\(y\)按位排序,依次相减。

也就是计算\(f_{i,j}\)表示\(l\)\(r\)的所有数中,数位第\(i\)大的数大小为\(j\)的方案数。

考虑枚举\(j\),数位dp。区间的数可以转化为前缀的数。

计算\(dp_{i,x,y}\)表示考虑了前\(i\)位,比\(j\)小的有\(x\)个,和\(j\)一样的有\(y\)个。

为了比较和\(r\)的大小,还要记录一位\(flag\)表示前\(i\)位是否和\(r\)一样。

T300680 C

最简单的一道题,但博弈论并不是我擅长的板块,所以考场弃了......

显然,如果初始时找不到\(k\times k\)的没有任何一个棋子的矩阵,那么先手必败。

如果能找到一个点,使得在这个点上放一枚棋子,导致找不到\(k\times k\)的没有任何一个棋子的矩阵,那么先手必胜。

除去这两种情况,初始局面至少会存在两个不相交的没有棋子的\(k\times k\)的矩阵。以及必败条件可以改成操作后使得找不到两个\(k\times k\)的矩阵,使得这两个矩阵全空且没有交。

那么考虑最后一步,肯定是只剩下了两个没有交的\(k\times k\)的矩阵。及一共有\(2\times k\times k\)个位置没有棋子,其他位置都有棋子。

根据初始空位的奇偶性,很容易得出最后一步是谁,从而得出谁必胜。

复杂度 \(O(n^2)\)

posted @ 2023-07-17 23:08  HQJ2007  阅读(44)  评论(0)    收藏  举报