W
H
X

NOIP2020前整理的一些题目

动态规划

ARC101C Ribbons on Tree(2020-11-27)

ARC101C Ribbons on Tree

key:容斥,状态设计

容斥是比较好想的,状态比较奇怪

如果是 \(n\) 个点随便连的话,方案数很好计算

\(f_{i,j}\) 表示 \(i\) 的子树内,\(i\) 所在连通块大小为 \(j\),其他连通块的方案(累乘,算上容斥系数)

\(f_{i,0}\) 表示 \(i\) 到父亲节点的边断了,这时候容斥系数乘上 \(-1\)。其他转移乘上 \(1\),背包合并。

AGC030F Permutation and Minimum(2020-11-25)

AGC030F.Permutation and Minimum

key:从大到小消除后效性

发现有三种数对:分别有0、1、2个位置已经确定了

有2个位置确定的扔掉就是,剩下两种。dp也是以这两种数对的个数为状态

\(f_{i,j,k}\) 为考虑了 \(i\) 个数,\(i\) 个数中有 \(k\) 对初始确定了一个的,\(k\) 对初始确定了0个,之后确定了 \(1\) 个的

初始的时候啥都没有,\(f_{0,0,0} = 1\)

关键点在于数要从大到小考虑,消除后效性

还有一个点是对于两个都没确定的,最后相对顺序不一定,答案乘上阶乘

转移暴力分类

ARC108E - Random IS(2020-11-22)

ARC108E - Random IS

key:设计合适的状态,数据结构维护

\(f_{l,r}\) 表示选了 \(l,r\)\([l+1,r-1]\) 内被选中的期望个数

变成区间dp,朴素做法就是枚举中间点转移

选了 \(l,r\) 后,\([l+1,r-1]\) 内能选的有 \(x\) 个,每次转移乘上系数 \(\frac{1}{x}\)\(n^3\)

对每个点建立四棵树状数组,以这个点为左端点两棵分别记录能选的个数,能选的 \(f\) 的和。以它为右端点同理

AGC049D - Convex Sequence(2020-11-15)

D - Convex Sequence

key:可用的物品只有 \(\sqrt{n}\) 种,对 \(g\) 的定义优化

其实就是相邻两个数的差值单调,假设已经确定最低点的位置 \(w\)(如果有多个最低选最左边的)和最小值 \(val\),且初始时所有都为 \(val\)

可以进行一下操作若干次:

1、在 \([1,w-1]\) 选择一个 \(x\),对 \(x,x-1,x-2...\) 分别加上 \(1,2,3...\)

2、在 \([w+1,n]\) 选择一个 \(x\),对 \(x,x+1,x+2...\) 分别加上 \(1,2,3...\)

因为总和为 \(m\),相当于只有 \(2\times \sqrt{m}\) 种有效商品,可以预处理出 \(f_{i,j}\) 表示用前 \(i\) 种小的物品,总和为 \(j\) 的方案数

因为 \(w\) 为最小值的最左边,所以至少对 \(w-1\) 操作一次,因此 \(w\) 的取值至多也只有 \(2\times \sqrt{m}\)

枚举这个 \(w\),再枚举 \(val\) 和左边操作的和,左右相乘再相加,复杂度 \(n^2\)

其实 \(val\)\(val + 1\) 的区别相当于初始容量 \(-n\),在计算左边方案的时候直接让 \(g_i\) 表示和为 \(i-k\times n\) 的总方案数,\(val\) 就不用枚举了

AGC030D Inversion Sum(2020-11-24)

AGC030D Inversion Sum

key:转换为概率问题,想到概率均摊

表面上是统计数量,实际上是一个概率dp,因为每种情况概率相同,求出概率后乘上总方案数

\(f_{i,j}\) 表示 \(i\)\(j\) 大的概率,求出 \(f\) 后答案就出来了

对于每次操作 \(x,y\),只会对至少有一个是 \(x,y\) 的点对产生影响

产生的影响:1、对(x,y),概率重新均摊 2、其他的,(x,i)和(y,i)均摊,(i,x)和(i,y)均摊 暴力转移就ok啦~

AGC002F Leftmost Ball(2020-11-22)

Leftmost Ball

key:状态难想,转移方式难想。实力不足欸🤣

因为每种颜色的求会有一个白色,所以可以重新把球分类为白球和其他颜色,这两种球相对独立

这就是状态了:\(f_{i,j}\) 表示当前填了 \(i\) 个白球,\(j\) 类其他颜色的球的方案数 (其他颜色都是一下全部填完)

转移依据也比较奇特:按照当前空位最左边填什么转移。这样可以保证白球的合法性

如果填白的直接转,否则乘上一个组合数。当然其他颜色种类不能大于白球数量

AGC005D ~K Perm Counting(2020-11-21)

AGC005D ~K Perm Counting

key:容斥,把相互关联的数串成链,在链上dp

dp算出有至少 \(k\) 个不合法的方案进行容斥

在原序列上很难dp,把一些关联的数串成链

一个数 \(x\) 不可以填在 \(x+k\),也不可以填在 \(x-k\),就把这样一些数串起来,一个位置一个数值一个位置一个数值....

中间的边选了一条就代表一个不合法,不能选相邻两条边

这样每条链没有重复的部分。在每条链开头打上标记就可以拼接起来处理了。然后就是简单dp

\(f_{i,j,k}\) 表示前 \(i\) 个,选了 \(j\) 条,最后一条有没有选,在链头需要特判

CF1342F Make It Ascending(2020-11-16)

CF1342F Make It Ascending

key:代表元思想,贪心转移,dp状态

其实就是把这些树分成几部分,选一个数为代表,代表数单增

\(f_{i,j,k}\) 表示选了 \(i\) 部分,最后一个代表元位置为 \(j\),选了的数状态为 \(k\) 时最后一部分和的最小值

贪心:枚举最后一部分转移的时候代表元应该尽可能靠前(保证合法),给后面更多的可能,这个可以记录一些\(lowbit\),但要注意限制

然后枚举子集暴力转移就好了😁

CF1430G Yet Another DAG Problem(2020-11-10)

CF1430G Yet Another DAG Problem

先把边权转换为点权,点权的值域可以移到 \([1,n]\)

sol1.key:一些节点选了 \(x\) 的贡献 ————> 还没选的全部 \(+1\)

这个做法很好理解,只要预处理一下,然后枚举子集转移(枚举选了 \(i\) 的点的集合)。 \(3^n\)

sol2.key:把枚举集合改成一个点一个点加入降低复杂度,按照拓扑序操作避免不合法情况

先按照拓扑排序。\(f_{i,j,k}\) 表示当前考虑值选 \(i\) 的点,考虑到第 \(j\) 个,已经选的点状态为 \(k\) 时的最小值

想一想拓扑序的作用。对于边 \((u,v)\),有 \({val_u}>{val_v}\)

如果随便顺序枚举,可能先枚举到 \(v\),然后到 \(u\) 的时候,不知道 \(v\) 选的值是 \(i\) 还是 \(<i\),也就不能判断 \(val_u\)\(i\) 的合法性

但如果一定先枚举到 \(u\),此时 \(v\) 只要在 \(k\) 里就行,选的一定 \(<i\),一定合法

转移依旧是暴力转移😜。 复杂度 \(n^2\times 2^n\)

CF1442D Sum(2020-11-07)

CF1442D Sum

key:最多有一个数列只取了一部分,分治背包

每个数列都是单增的,如果存在两个都只取了一部分,其中某一个不取,取另一个后面的一定更优

分治思想就是对左边每列看成一个物品进行背包,然后考虑右边的某个数列只取一个。再反着来一遍

CF1389F Bicolored Segments(2020-11-02)

CF1389F Bicolored Segments

key:状态设定,线段树维护

肯定是一段颜色 \(1\),一段 \(2\),一段 \(1\) 交替出现

如果按照右端点排序从左往右扫一遍,能不能放只关心最右边一段的颜色

\(f_{i,j,k}\) 表示当前考虑到 \(i\)\([j+1,i]\) 的颜色都为 \(k\) 的数量

转移有 \(2\) 种:1、放一条颜色为 \(q\) 的和前面颜色为 \(q\) 的连在一起。 2、新开一个段,改变当前颜色

两个转移都可以用线段树维护,开两棵维护即可

ARC105F - Lights Out on Connected Graph(2020-10-23)

F - Lights Out on Connected Graph

key:把两个条件分开处理,容斥

状态压缩。条件是二分连通图,把二分和连通分开处理

\(g_i\) 表示点集为 \(i\),二分图的方案数,先预处理出点集中有多少边,然后枚举二分图的两部分的点集,连接两部分的点可以选也可以不选,加上 \(2^k\)

然后算 \(f_i\),发现 \(f_i\) 要从 \(g_i\) 中减去不连通的数量。任意枚举一个点(代码中是编号最小的)所在连通块的状态,其他部分随意,方案相乘再减掉

ABC176F - Brave CHAIN(2020-9-26)

F - Brave CHAIN

key:不断优化转移

转换原题意:初始有\(2\)张牌,每次操作拿\(3\)张牌并从\(5\)张牌中丢弃\(3\)张,如果\(3\)张一样得分\(+1\)

\(f_{i,j,k}\)表示进行\(i\)轮游戏后,手里剩下的牌为\(i\)\(j\)时的最大值,暴力复杂度\(O(n^5)\)

如果当前手中的牌为\(j,k\),每一轮新拿的三张牌是确定的,一轮过后的\(2\)张牌只能从\(5\)张中选,共\(10\)种情况,复杂度\(O(10\times n^3)\)

进一步优化,可以按照\(2\)张牌有几张来自新拿的\(3\)张进行分类加速转移

1、如果\(2\)张都来自新拿的,则可以从之前的任意状态进行转移,记录最大值即可。还要考虑丢弃的\(3\)张牌相同的情况分数\(+1\)

2、如果有\(1\)张牌来自新拿的,另一张牌为\(x\),说明\(x\)来自之前的牌,则必须从有\(x\)的状态进行转移(还是记录最大值)。同样特殊考虑\(3\)张牌相同进行额外转移

3、如果\(j,k\)均不来自新拿的,则丢弃的三张牌一定是新拿的,判断一下是否有分。从上一步的\(j,k\)转移

每次转移情况\(1\)的复杂度是常数,\(2\)的复杂度为\(O(n)\),但存在情况\(3\),复杂度并没有得到提高

\(3\)的所有转移形式一致,不用暴力算,用一个变量记录加的分就好了。但如果选择情况\(1,2\)就不能获得\(3\)的加分,在转移的时候减去

数据结构

CF1436E Complicated Computations(2020-11-20)

CF1436E Complicated Computations

key:分析 \(mex=x\) 的条件,用线段树维护最后位置

只要算出每种值是否\(mex\)的出来。对于 \(mex=x\) 的一段,要有所有的 \([1,x-1]\),不能有 \(x\),大于 \(x\) 的随意

用线段树维护每个数最后出现的位置,从左到右扫描整个序列

扫到 \(i\),查一下 \([1,{a_i}-1]\) 的最后位置最小值,如果大于 \(a_i\) 的最后位置,说明 \(a_i\) 搞定了,然后更新一下

注意最后要对每个值扫一遍(最后一段)

CF1303F Number of Components(2020-11-18)

CF1303F Number of Components

key:并查集只能快速维护加边,正反分别做一次全部转换为加边

特殊性质是每一次更改的颜色是单调不降的

正着做一遍,每次操作变成当前操作颜色的加边

反着做一遍,变成之前颜色的加边

没有切断操作了,直接并查集维护一下

CF1004F Sonya and Bitwise OR(2020-11-12)

[CF1004F Sonya and Bitwise OR](CF1004F Sonya and Bitwise OR)

key:\(or\)操作只会在最多 \(log\) 个位置改变值

发现这个性质之后,线段暴力维护每个点左右发生改变的位置。合并的时候一个个暴力算。哭笑不得😂这个性质还是可以记一下的

P4587 [FJOI2016]神秘数(2020-10-18)

P4587 [FJOI2016]神秘数

key:迭代查询最多 \(log\)

其实查询 \(l,r\),就是找到第一个 \(x\),使 \([l,r]\) 内所有 \(\leq x\) 的数的和 \(<x\)

查询 \(l,r,x\) 可以用主席树维护

初始 \(res=1\),如果满足就输出,否则 \(res=res+sum\)\(sum\) 就是 \([l,r]\) 内所有 \(\leq x\) 的数的和

每次不满足都至少变为 \(2\) 倍,最多查询 \(log\)

杂题

11-27 T4(2020-11-30)

T4

key:高维前缀和,容斥

同时满足两个条件,比较复杂。不如算出不符合的

但对第一个条件,\(x\) 不能取的部分是 \({a_i}\) \(xor\) \(x\),必须取的是 \(a_i\) \(xor\) \(y\)

如果这两部分重合就挂了。

高维前缀和跑一跑,按照 \(1\) 个奇偶容斥一下

AGC014B Unplanned Queries(2020-11-24)

AGC014B Unplanned Queries

先把一条路径的弄成两个点分别到根的,如果一个点的子树里所有边都满足条件,那么这个点向上连的边一定被经过偶数次,则这个点也一定是偶数次,统计一下判断

AGC020C Median Sum(2020-11-24)

AGC020C Median Sum

key:想到对称性,只需要\(01\)状态用 \(bitset\) 优化

如果暴力求出每种和有多少方案是 \(n^3\)

有一个非常好的性质,因为是所有子集,所以用 \(f_i\) 来表示 \(i\) 是否能到达,\(f\) 数组一定是对称的

要求中位数,直接从中间开始扫到第一个。用bitset优化 \(f\) 的计算

CF1451E Bitwise Queries(2020-11-22)

CF1451E Bitwise Queries

E1.key:通过位运算结果的每种方案分类确定一个数,后面全部xor

这个做法比较无脑,就是弄出 \(1\)\(2\)\(2\)\(3\)\(1\)\(3\) 的一些结果,对每一位分类算出 \(1\)\(2\),后面 \(xor\)

E2.key:先算出一个后面xor不变,但通过一写特殊值快速算

E2和E1差别挺大的,在E1的基础上是想不出E2的,被坑了。。。

改一下顺序,先对所有数和 \(1\) 查询\(xor\),然后要算出 \(1\) 的值

1、如果原序列有两个值相同

找到这两个,\(or\)一下,再推出第 \(1\) 个,共用 \(n\) 次查询

2、全都不同

一定有 \(2\) 个数\(xor\)值为全 \(1\),这两个数对\(xo\)r的值再\(xor\)也一定是全 \(1\),分别和 \(1\) 查询\(and\),再或起来就是 \(1\),共用 \(n+1\)

CF1354G Find a Gift(2020-11-14)

CF1354G Find a Gift

key:先确定第一个,后面倍增

如果第一个确定不是礼物,后面直接倍增先确定范围,再在范围内二分

有个条件就是石头多于一半。将第一个随机与 \(30\) 个比较,如果都相等,那只有 \(\frac{1}{2^30}\) 的概率是礼物,直接当成石头

CF1437E Make It Increasing(2020-11-10)

CF1437E Make It Increasing

key:找到数值与下标的关系,转换成经典问题

首先肯定按照固定点拆成几小段。如果满足条件,其实就是 \({a_i}-i\) 要单调不降。然后用总长度减去\(LIS\)(非严格)

ACL1E - Shuffle Window(2020-9-22)

E - Shuffle Window

kel:对原问题转化,

跟“逆序对”关联的是每两个数的相对位置(前后关系),所以只要求出每两个数相对位置发生改变的概率

先把原本打乱序列的过程进行转换,发现等价于:

有一个集合\(s\)和一个初始为空的序列\(a\),初始时\(s\)\(1—k\) \(k\)个元素, 进行\(n-k\)次操作,第\(i\)次从\(s\)中随机删除一个位置,并插入\(k+i\)

有了这样的转化,就可以简单的算出对于\(i<j\)\(i、j\)相对位置改变的概率

首先,如果两个数要改变相对位置,那么必须存在一个时刻,他们同时在集合中。设\(t[i]\)为第\(i\)个位置加入集合的时间

每次会随机从\(k\)个数中选出\(1\)个踢出集合,留下的概率是\(\frac{k-1}{k}\),如果\(i,j\)要同时存在于集合中,则从\(i\)加入集合到\(j\)加入集合间的\(j-i\)次操作,\(i\)都不能被踢出集合,概率为\({(\frac{k-1}{k})}^{t[j]-t[i]}\)

如果两个数都在集合中,改变的概率为\(0.5\)

把上述式子的\(i,j\)分开,可以从\(1—n\)遍历\(j\),准便用树状数组求出\(i\)部分的贡献

图论

星际战争(2020-11-24)

星际战争

key:观察到边和点的数量差小,想到用\(bfs\)建树

边比点多不了多少,想到建立一颗生成树,剩下一些边特殊处理

为了让树上的点到1的距离单调,要用\(bfs\)来建树

建完之后还有一些特殊边,对应一些特殊点

因为到 \(1\) 的距离单调,可以从当前点不断向上直到与黑暗势力相撞,那这一颗子树里都可以保护。同时还可以通过特殊边走到特殊点控制其他一些树

\(dfn\)序后每棵子树变成一段区间,\(sort\)一下去重计算

CF1354E Graph Coloring(2020-11-13)

CF1354E Graph Coloring

key:把三种点转换成 \(2\)

可以把 \(1,3\) 当作一种,转换成二分图。后面背包判定一下就ok啦

网络流

一些正解不是网络流(状压之类),\(n\) 比较小且可以把限制转换成连边的问题用网络流来搞好理解还不慢

CF1430G Yet Another DAG Problem(2020-11-10)

CF1430G Yet Another DAG Problem

key:根据最小割贪心的性质把限制连边

这个的正解是拓扑+状压dp,然后可以这么搞:

把边的贡献放到点上,点权的值域和点的个数同级且非常少,把每个点选每个值的贡献当作边建图

但是有限制,即一条边的 \(u\) 的值大于 \(v\) 的值。可以再 \(v\) 选每个值 \(p\) 的地方向 \(u\)\(p+1\) 的地方连 \(inf\)

然后求最小割。这个限制相当于如果 \(v\) 取了 \(p\),那 \(u\)\(p\) 之前的都是白取,不会算在最小割内

注意点是每条边的权值要平移至正数

找方案有点疑惑。。。

CF1354F Summoning Minions(2020-11-14)

CF1354F Summoning Minions

key:二分图

这个题自己想了一半,但最后建图不是像上面那样拆开,没有想出来,但其实dp更简单

先贪心一波,假设最后留下的 \(k\) 个点已经选好了,最优方案把这些点按照 \(b_i\) 排序,前 \(k-1\) 个在最开始放入,然后随便放入没有选中的点(放入马上删除),最后放入第 \(k\) 个点

先假设所有点都没被选中,按照公式算出总答案,用网络流跑选 \(k\) 个点的最优解。发现把第 \(i\) 个点选成 \(k\) 中第 \(j\) 个带来的变化是可以算的,这个自然作为边权

与上面不同的是,如果拆开每个点,每个点只能选一次的限制不是很好考虑。其实方法比上面更简单,直接用二分图解决。左部 \(n\) 个点为每个点,右部 \(k\) 个点为把它选中为第几个,连边跑费用流~~~

ARC107F - Sum of Abs (2020-11-02)

F - Sum of Abs

和上一题比较类似,先把所有的弄成某个状态,然后把改变状态带来的改变价值当作边权,但是这个稍微难理解一些。

一个连通块中,如果总和是负数,相当于所有点的权值 \(\times -1\),否则 \(\times 1\)

在答案中每个点都是被成上了 \(+1\)\(-1\) 的权值或被删除,三种状态。限制是没删除的相连的点乘上的值相同

先建立基本的模型,对于每个点拆成 \(2\) 个,从源点到第一个点,从第一个点到第二个点,从第二个点到汇点,代表 \(3\) 中状态

一开始的答案为所有点的绝对值之和,那么网络流模型中每条边的边权是可以弄出来的。

只剩下添加限制了。设从第一个点连到第二个点的表示删除的代价。对于每条边 \((u,v)\),从 \(u\) 的二号点到 \(v\) 的一号点连 \(inf\) 边,从 \(v\) 的二号点到 \(u\) 的一号点连 \(inf\)

意义就是如果 \(u\) 选择删除,\(v\) 随意(因为从一号到二号的边已经没了),如果选了 \(+1\)\(-1\)\(v\) 只能删除或选同样的权值(如果选了不同的两边还是通的,没有意义)。跑最小割就是答案

博弈游戏

AGC048D - Pocky Game(2020-10-26)

D - Pocky Game

key:基于贪心的dp

\(a_{i,j}\) 表示 \(A\) 先手,只考虑 \([l,r]\) 这段,\(A\) 要获胜第 \(i\) 个位置至少有多少石子,\(b_{i,j}\) 同理

肯定是越多越有利,因为一次可以拿任意多个,太多了也不会导致结果变差,所以这个状态是挺合理的

按照一般的区间dp转移,设第 \(i\) 个位置有 \(c_i\) 个石子,分类讨论

1、如果 \({c_j} < {b_{i+1,j}}\),那不管第 \(i\) 个位置有多少,直接拿光就赢了(\([l+1,r]\) 这段B先手赢不了),有 \(a_{i,j}=1\)

2、\({b_{i+1,j}} \leq {c_j}\),这时候要考虑两个点:

Ⅰ、和A消耗,一个一个拿,此时为了让消耗玩后 \({c_j} < {b_{i+1,j}}\),至少要 \({c_j} - {b_{i+1,j}} + 1\)

Ⅱ、消耗结束,B知道自己在 \([l+1,r]\) 赢不了,干脆把第 \(j\) 堆直接拿完,变成 \([l,r-1]\) 的A先手的游戏,此时为了胜利,消耗完后至少还要 \(a_{i,j-1}\)

综上,第二种情况 \(a_{i,j}={c_j} - {b_{i+1,j}} + 1 + a_{i,j-1}\)

ARC105E - Keep Graph Disconnected(2020-10-18)

E - Keep Graph Disconnected

key:奇偶分析

游戏的最后状态肯定只存在两个联通块,一个包含 \(1\),一个包含 \(n\), 且块内的边都连满了

可以用完全图的边数减去没有连的边,设最后两个块大小为 \(a,b\),则总边数 \(sum = \frac{n\times (n-1)}{2} - a\times b\)

输赢和 \(sum\) 的奇偶有关,可以想到把 \(n\) 也分为两类讨论

1、\(n\) 为奇数:\(a,b\) 一定是一奇一偶,那么 \(sum\) 奇偶确定,答案也就确定

2、\(n\) 为偶数比较麻烦:

假设初始时 \(1\)\(n\) 所在的连通块大小分别为 \(x,y\),根据 \(x,y\) 的奇偶性再分两类:

A、\(x,y\) 一奇一偶,剩下的点为奇数个。所以奇数的联通块有奇数个,偶数的连通块若干,只有奇数可以改变奇偶性

此时先手可以把 \(x\times y\) 变成自己想要的奇偶,如果要变成奇+奇,就先连一个奇数块到偶的那个,否则把一个奇数块连到奇数的那个

然后如果后手连了一个奇数块,则先手也连一个奇数块到同一个(剩下偶数块,可以一一配对),奇+奇=偶,奇偶性不变,否则连其他的。

B、\(x,y\) 奇偶性相同,若 \(x,y\) 都为奇数,则想要两个奇数的获胜,否则想要两个偶数的获胜,证明和上面差不多。。。

ARC105D - Let's Play Nim (2020-10-16)

D - Let's Play Nim

key:奇偶分析,两两配对

有两个结论

1、\(n\) 为奇数,后手必胜。此时相当于先手多放一次硬币,但从后手开始取,所以后手要保证所有堆的异或和不为 \(0\)。假设先手第一次放在了第 \(x\) 堆,则后手每一次都选择当前最大的放入第 \(x\) 堆,保证最后这一堆的数量大于其他所有的和,这样异或和一定不为 \(0\)

2、\(n\) 为偶数,此时先手开始取。若所有数可以成双配对,则后手取胜,每次只要选一样的放就可以保证异或和为 \(0\)。否则先手获胜,和第一种类似,每次选取最大的放入同一堆,则这一堆一定大于其他所有的和

posted @ 2020-11-13 21:12  -敲键盘的猫-  阅读(325)  评论(1编辑  收藏  举报