哎
哎
[NOIP2021] 数列
对于二进制进行 \(dp\),考虑从低位向高位进行 \(dp\) 。
考虑到这样的难点在于进位,进位会对后面很多位都产生影响。
考虑如何消去这些影响,我们可以直接将影响存下来,也就是直接压进状态中。
设 \(f_{i,j,p,k}\) 表示二进制的第 \(i\) 位,后面对这位进了 \(j\) 位,用了 \(p\) 个位置,目前有 \(k\) 个 \(1\) 的方案的积之和。
有了这个定义转移就很简单了,考虑往后转移,将枚举相同的数放的个数即可,第 \(i\) 个数放了 \(g\) 个,则。
时间复杂度 \(O(n^4m)\)
[CSP-S2019] Emiya 家今天的饭
将题目转化为有 \(n\) 行 \(m\) 列的表格,每行最多选 \(1\) 个,每列选的不能超过所选的一半。
注意到 一半 是一个很特别的东西,保证了如果有一列不合法,则最多只有一列不合法。
所以我们可以用所有方案数减去不合法的方案数。
枚举哪一列是不合法的,考虑我们要怎么统计。
注意到我们的一半是相对而言,和总选数有关,考虑到一列的方案数也不是之和个数有关,没办法简单地进行单独处理。
所以考虑压进状态中,\(f_{i,j,k}\) 表示前 \(i\) 行中,不合法的列中选了 \(j\) 个,其它的选了 \(k\) 个。
这样就很好地处理了,此时时间复杂度 \(O(nm^2)\),注意到答案只和后两维的差有关,合并一下,将后面两维合并成差的一维即可。
时间复杂度 \(O(n^2m)\) 。
ARC104D Multiset Mean
感觉自己脑子爆了,想哭。
首先枚举平均数 \(x\),将所有 \(a_i\) 变为 \(a_i-x\) 。
接着设计一个 \(dp\) , \(f_{i,j}\) 表示前 \(i\) 个数,和为 \(j\) 的方案数。
容易发现答案为 \(f_{n,0}\),这个暴力 \(dp\) 的时间复杂度是 \(O(n^4m^2)\)
考虑优化,我们注意到这样一个事情:
容易发现所有转移过来的状态的 \(j\) 都是模 \(a_i\) 意义下同余的,也就是说我们对于同余的数字快速做前缀和就好了。
这时时间复杂度 \(O(n^4k)\),还是不太行。
考虑我们减去 \(x\) 的本质是什么,是将值域变为了 \([1-x,-1],[0,0],[1,n-x]\),发现前面和后面的绝对值相同,所以只要 \(dp\) 预处理一下,然后把值域对应上去和相同的一乘就好了。
时间复杂度 \(O(n^3k)\),感觉这题的难点就是前缀和优化和发现减 \(x\) 后值域没有本质的改变,正和负都是等价的。
ABC317F Nim
急了,深切得感受到了自己对于数位 \(dp\) 的不熟。
考虑到倍数这东西是一个乘的关系,而异或又是一个位的关系,这两个并不太好联系起来。
直接数位 \(dp\),将余数压进状态里,可得 \(f_{pos,y1,y2,y3,lmt1,lmt2,lmt3,lead1,lead2,lead3}\)。
表示在第 \(pos\) 位,三个的余数为 \(y\),是否顶上界,是否又前导 \(0\),最后结束状态要保证 \(3\) 个数都非 \(0\)。
[福建省队集训2019] 最大权独立集问题
题意可以转化为给一颗树,给树上的每条边定向,点 \(i\) 可以到达 \(k_i\) 个点,要使得 \(\sum d_ik_i\) 最大。
首先分析一下一条边定向的影响。
1.父亲连向儿子,则父亲能到达儿子能到达的所有状态。
2.儿子连向父亲,则儿子能到达父亲能到达的所有状态。
若只关心父亲连向儿子就很容易写出一个树形 \(dp\) 出来。
用 \(f_{i,j}\) 表示点 \(i\) 向下能到达 \(j\) 个点时,子树的 \(\sum d_ik_i\) 最大值。
但是这样无法处理儿子连向父亲的情况,考虑增加状态。
考虑到这个状态行不通的原因是不知道一个点向上能走多少个点,也就是说不知道总共能走多少个点。
注意到每个点最后能走的点数都和相邻的点的最终点数有关,考虑把这个设进状态里。
\(f_{i,j,k}\) 表示点 \(i\),目前能走 \(j\) 个点,最终能走 \(k\) 个点。
在最初始的时候就可以将 \(d_i\) 的贡献算进去,设父亲为 \(u\),儿子为 \(v\),对于两种定向容易有转移:
到最后答案就是 \(\max f_{1,i,i}\),时间复杂度 \(O(n^3)\),感觉这题的难点是题意转化和将未知量的最终状态设进状态中。
[NOIP2021] 方差
技巧性很强的一道 \(dp\)。
首先发现题目中的操作就相当于交换两个差分,意味着我们可以任意重排这个差分序列。
然后再化简一下题目的贡献形式,\(ans=n\sum a_i^2-(\sum a_i)^2\)。
我们固定其中一项,\(f_{i,j}\) 表示放了 \(i\) 个差分,\(\sum a_i\) 的值为 \(j\) 时,\(\sum a_i^2\) 的最小值。
但是这样转移无从下手,在做排列顺序的 \(dp\) 题时有一个常用的技巧,从最终状态入手。
结论:最优解的差分序列一定是单谷的。
比较感性的理解就是这样能使离散程度最小。
我们将差分序列排序,在放第 \(i\) 个差分时,一定是放在序列的末尾或开头。
有了这个,我们可以直接推出转移方程。
P4766 [CERC2014] Outer space invaders
将外星人离散化之后用,\(f_{l,r}\) 表示解决出现与消失均在 \([l,r]\) 的外星人的最小代价。
显然有转移 \(f_{l,r} = \min f_{l,k-1}+d_k+f_{k+1,r}\),\(d_k\) 表示被包含在 \([l,r]\) 的外星人的最大距离。
显然直接硬维护这东西很麻烦,一般做法都只能做到 \(O(n^3logn)\)。
正确的做法是对于一个区间 \([l,r]\) 中找到距离最大的外星人所存在的区间,只在里面枚举断点。
考虑换一种角度来看操作的过程,首先明确一点,就是只对于 \([l,r]\) 中距离最大的一定有一次针对其的操作,并且操作的顺序没有关系。
所以就可以看做每一个区间都去操作里面最大的,也就优化了前面每一种都操作的情况。
也就是说原来的做法中不是最大值的外星人是被重复枚举了,实际上这些不是最大值的外星人会正确的做法中在子区间中成为最大值被操作。
直接区间 \(dp\),时间复杂度 \(O(n^3)\) 。