NOIP2020前整理的一些题目
动态规划
ARC101C Ribbons on Tree(2020-11-27)
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)
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)
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)
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)
key:状态难想,转移方式难想。实力不足欸🤣
因为每种颜色的求会有一个白色,所以可以重新把球分类为白球和其他颜色,这两种球相对独立
这就是状态了:\(f_{i,j}\) 表示当前填了 \(i\) 个白球,\(j\) 类其他颜色的球的方案数 (其他颜色都是一下全部填完)
转移依据也比较奇特:按照当前空位最左边填什么转移。这样可以保证白球的合法性
如果填白的直接转,否则乘上一个组合数。当然其他颜色种类不能大于白球数量
AGC005D ~K Perm Counting(2020-11-21)
key:容斥,把相互关联的数串成链,在链上dp
dp算出有至少 \(k\) 个不合法的方案进行容斥
在原序列上很难dp,把一些关联的数串成链
一个数 \(x\) 不可以填在 \(x+k\),也不可以填在 \(x-k\),就把这样一些数串起来,一个位置一个数值一个位置一个数值....
中间的边选了一条就代表一个不合法,不能选相邻两条边
这样每条链没有重复的部分。在每条链开头打上标记就可以拼接起来处理了。然后就是简单dp
\(f_{i,j,k}\) 表示前 \(i\) 个,选了 \(j\) 条,最后一条有没有选,在链头需要特判
CF1342F Make It Ascending(2020-11-16)
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)
key:最多有一个数列只取了一部分,分治背包
每个数列都是单增的,如果存在两个都只取了一部分,其中某一个不取,取另一个后面的一定更优
分治思想就是对左边每列看成一个物品进行背包,然后考虑右边的某个数列只取一个。再反着来一遍
CF1389F Bicolored Segments(2020-11-02)
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)
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)
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)
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)
key:高维前缀和,容斥
同时满足两个条件,比较复杂。不如算出不符合的
但对第一个条件,\(x\) 不能取的部分是 \({a_i}\) \(xor\) \(x\),必须取的是 \(a_i\) \(xor\) \(y\)
如果这两部分重合就挂了。
高维前缀和跑一跑,按照 \(1\) 个奇偶容斥一下
AGC014B Unplanned Queries(2020-11-24)
先把一条路径的弄成两个点分别到根的,如果一个点的子树里所有边都满足条件,那么这个点向上连的边一定被经过偶数次,则这个点也一定是偶数次,统计一下判断
AGC020C Median Sum(2020-11-24)
key:想到对称性,只需要\(01\)状态用 \(bitset\) 优化
如果暴力求出每种和有多少方案是 \(n^3\) 的
有一个非常好的性质,因为是所有子集,所以用 \(f_i\) 来表示 \(i\) 是否能到达,\(f\) 数组一定是对称的
要求中位数,直接从中间开始扫到第一个。用bitset优化 \(f\) 的计算
CF1451E Bitwise Queries(2020-11-22)
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)
key:先确定第一个,后面倍增
如果第一个确定不是礼物,后面直接倍增先确定范围,再在范围内二分
有个条件就是石头多于一半。将第一个随机与 \(30\) 个比较,如果都相等,那只有 \(\frac{1}{2^30}\) 的概率是礼物,直接当成石头
CF1437E Make It Increasing(2020-11-10)
key:找到数值与下标的关系,转换成经典问题
首先肯定按照固定点拆成几小段。如果满足条件,其实就是 \({a_i}-i\) 要单调不降。然后用总长度减去\(LIS\)(非严格)
ACL1E - Shuffle Window(2020-9-22)
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)
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)
key:二分图
这个题自己想了一半,但最后建图不是像上面那样拆开,没有想出来,但其实dp更简单
先贪心一波,假设最后留下的 \(k\) 个点已经选好了,最优方案把这些点按照 \(b_i\) 排序,前 \(k-1\) 个在最开始放入,然后随便放入没有选中的点(放入马上删除),最后放入第 \(k\) 个点
先假设所有点都没被选中,按照公式算出总答案,用网络流跑选 \(k\) 个点的最优解。发现把第 \(i\) 个点选成 \(k\) 中第 \(j\) 个带来的变化是可以算的,这个自然作为边权
与上面不同的是,如果拆开每个点,每个点只能选一次的限制不是很好考虑。其实方法比上面更简单,直接用二分图解决。左部 \(n\) 个点为每个点,右部 \(k\) 个点为把它选中为第几个,连边跑费用流~~~
ARC107F - Sum of Abs (2020-11-02)
和上一题比较类似,先把所有的弄成某个状态,然后把改变状态带来的改变价值当作边权,但是这个稍微难理解一些。
一个连通块中,如果总和是负数,相当于所有点的权值 \(\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)
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)
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)
key:奇偶分析,两两配对
有两个结论
1、\(n\) 为奇数,后手必胜。此时相当于先手多放一次硬币,但从后手开始取,所以后手要保证所有堆的异或和不为 \(0\)。假设先手第一次放在了第 \(x\) 堆,则后手每一次都选择当前最大的放入第 \(x\) 堆,保证最后这一堆的数量大于其他所有的和,这样异或和一定不为 \(0\)
2、\(n\) 为偶数,此时先手开始取。若所有数可以成双配对,则后手取胜,每次只要选一样的放就可以保证异或和为 \(0\)。否则先手获胜,和第一种类似,每次选取最大的放入同一堆,则这一堆一定大于其他所有的和