乱七八糟的DP题随便刷刷
文章目录
- CF148E - Porcelain
- CF1131D - Gourmet choice
- CF629C - Famil Door and Brackets
- CF895C - Square Subsets
- CF1012C - Hills
- CF985E - Pencils and Boxes
- CF374C - Inna and Dima
- CF402D - Upgrading Array
- CF362C - Insertion Sort
- CF533B - Work Group
- CF1152D - Neko and Aki's Prank
- CF730J - Bottles
- CF8C - Looking for Order
- CF1067A - Array Without Local Maximums
- CF930C - Teodor is not a liar!
- CF1611G - Robot and Candies
- CF510D - Fox And Jumping
- CF568B - Symmetric and Transitive
- CF963B - Destruction of a Tree
- CF353D - Queue
CF148E - Porcelain
题意:
- 有 n n n 层货架,每层上有 k i k_i ki 个东西,每个东西存在一个价值 v i v_i vi。
- 现在至多可以拿 m m m 个东西,每一次只能从货架的最左或最右端拿走,求可以拿到的最大价值
- n , k , v i ≤ 100 , m ≤ 10000 n,k,v_i \leq 100,m \leq 10000 n,k,vi≤100,m≤10000
思路:
-
首先可以明确,第 i i i 层拿 j j j 个东西的最优价值都是确定的,我们只需要 O ( n 3 ) O(n^3) O(n3) 枚举当前第 i i i 层拿 j j j 个东西,左边选了 k k k 个即可。
-
接着我们可以把第 i i i 层的 k i k_i ki 个东西看一组物品,那么就变成了以选取物品个数为体积,物品价值为重量的一个分组背包问题,复杂度 O ( n m k ) O(nmk) O(nmk)
注意分组背包先枚举第几组,再倒序循环体积,最后在枚举组内物品
CF1131D - Gourmet choice
题意:
- 有两个正整数序列 a , b a,b a,b,长度分别为 n , m n,m n,m,现在给出给出所有 a i a_i ai 与 b j b_j bj 的大小关系,构造出最大元素最小的方案
- 其中大小关系包含大于,小于以及等于
- n , m ≤ 1000 n,m \leq 1000 n,m≤1000
思路:
-
如果大小关系中没有等于,我们很容易想到直接在 D A G DAG DAG 上做 d p dp dp,令 f [ u ] f[u] f[u] 代表点 u u u 的最终答案,则 f [ t o ] = m a x ( f [ t o ] , f [ u ] + 1 ) f[to]=max(f[to],f[u]+1) f[to]=max(f[to],f[u]+1),并且通过出队列数判断是否无解
-
那么现在的问题就是考虑:如果解除等于这一关系限制?
考虑到没法直接连边,但是把相当的点看作一个点集,那么这个点集与此外其他点的关系就很好处理了,并且一个点集内的相互关系我们可以不用处理。于是我们可以使用缩点来处理所有值相等的点 -
我一开始是用并查集直接维护一个点集的最大值,零入度的点个数以及点集个数,然后整个点集的点都符合零入度了就一起得到最终答案并且入队列。。。。。这样显然很麻烦,可以在一开始就把他们缩成一个点,然后直接 D A G DAG DAG 上 d p dp dp 即可,非常无脑
CF629C - Famil Door and Brackets
题意:
- 给出一个长度为 m m m 的只包含 ′ ( ′ '(' ′(′ 和 ′ ) ′ ')' ′)′ 的序列 S S S,要求构造只包含 ′ ( ′ '(' ′(′ 和 ′ ) ′ ')' ′)′ 的序列 P , Q P,Q P,Q,使得按照 P , S , Q P,S,Q P,S,Q 顺次连接得到长度为 n n n 的合法括号序列 S ′ S' S′,其中 P , Q P,Q P,Q 都可以为空
- 1 ≤ m ≤ n ≤ 1 0 5 , n − m ≤ 2000 1 \leq m \leq n \leq 10^5,n-m \leq 2000 1≤m≤n≤105,n−m≤2000
思路:
-
设平衡度为左括号与右括号的个数之差,考虑到 n − m ≤ 2000 n-m \leq 2000 n−m≤2000 ,我们枚举第一个序列 P P P 的长度与平衡度,那么 Q Q Q 的状态也已经知道了,我们利用乘法原理求出方案数即可
-
序列 P P P 需要满足的要求:
1.所有位置的平衡度都要恒大于 0 0 0
2.如果序列 S S S 所有位置的最小平衡度 b b b 小于 0 0 0,那么序列 P P P 的整体平衡度必须大于 P P P,相当于给 S S S 作铺垫以保证最终 S ′ S' S′ 是合法序列 -
序列 Q Q Q 需要满足的要求:
1.所有位置的平衡度都要恒大于 P + S P+S P+S 最终的平衡度的相反数
2. P + S + Q P+S+Q P+S+Q 最终的平衡度为 0 0 0 -
显然对于 P P P,我们只需要按照构造合法括号序列的方法,设 d p [ i ] [ j ] dp[i][j] dp[i][j] 代表前 i i i 个平衡度为 j j j 的方案数, e z : d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j + 1 ] ez:dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1] ez:dp[i][j]=dp[i−1][j−1]+dp[i−1][j+1],显然 P P P 的方案数就是 d p [ i ] [ j ] dp[i][j] dp[i][j]。
-
那么对于 Q Q Q,如果正着看显然每次都要按照 P + S P+S P+S 最终的平衡度做一次dp,但是如果我们把原串反转过来,把前缀的定义也反转,那么方案数就是 d p [ n − m − i ] [ j + c n t ] dp[n-m-i][j+cnt] dp[n−m−i][j+cnt] 其中 c n t cnt cnt 为 S S S 的平衡度。这里没有具体的什么证明解释,感性理解就好hh。
CF895C - Square Subsets
题意:
- 对于一个长度为 n n n 的数组 a a a,求从 a a a 中选择一个非空子集满足两两乘积为平方数的方案数
- 1 ≤ n ≤ 1 0 5 , 1 ≤ a i ≤ 70 1 \leq n \leq 10^5,1 \leq a_i \leq 70 1≤n≤105,1≤ai≤70
思路:
看到 a i ≤ 70 a_i \leq 70 ai≤70 质因子就 19 19 19 个,第一眼状压dp。。。
具体来说,平方数的每个质因子个数都为偶数,那我们只需要判断子集的质因子的奇偶即可。
我们设二进制数 m a s k mask mask 代表一个集合的质因子的奇偶性,那么第 i i i 个质因子为奇数则设为 1 1 1,那么显然根据奇偶关系,两个集合合并 m a s k mask mask 应该做异或操作。
设前 f i , m a s k f_{i,mask} fi,mask 为前 i i i 个数中质因子奇偶情况为 m a s k mask mask 的方案数,则 f i , m a s k ⊕ x = f i , m a s k ⊕ x + f i − 1 , m a s k f_{i,mask \oplus x}=f_{i,mask \oplus x}+f_{i-1,mask} fi,mask⊕x=fi,mask⊕x+fi−1,mask,其中 x x x 代表第 i i i 个数的质因子奇偶情况。但是这么做复杂度显然 O ( 1 0 5 × 1 0 6 ) O(10^5 \times10^6) O(105×106) 太夸张了,完全没必要一个一个数去枚举,因为值域只有 70 70 70,且子集方案数与顺序无关,我们直接枚举值即可。
那么新问题又来了。。对于值 v a l val val,有 k k k 个这样的数加入到之前的的子集中,由于遵循异或的规律,那么加入奇偶个数的数结果都不同,也就是说大致分成以下两种情况:
- ∑ i ≤ k , i ≡ 1 ( m o d 2 ) C k i = 2 k − 1 \sum_{i \leq k ,i\equiv 1 \ (mod 2)} C_k^i=2^{k-1} ∑i≤k,i≡1 (mod2)Cki=2k−1 ( m a s k mask mask 异或上 v a l val val 的奇偶情况 x x x)
- ∑ i ≤ k , i ≡ 0 ( m o d 2 ) C k i = 2 k − 1 \sum_{i \leq k ,i\equiv 0 \ (mod 2)} C_k^i=2^{k-1} ∑i≤k,i≡0 (mod2)Cki=2k−1 ( m a s k mask mask 不变)
综上得到转移方程
{ f i , m a s k = f i , m a s k + f i − 1 , m a s k ∗ 2 k − 1 f i , m a s k = f i , m a s k + f i − 1 , m a s k ⊕ x ∗ 2 k − 1 \left\{ \begin{aligned} f_{i,mask}=f_{i,mask}+f_{i-1,mask}*2^{k-1}\\ f_{i,mask}=f_{i,mask}+f_{i-1,mask \oplus x}*2^{k-1}\\ \end{aligned} \right. {
fi,mask=fi,mask+fi−1,mask∗2k−1fi,mask=fi,mask+fi−1,mask⊕x∗2k−1
CF1012C - Hills
题目描述:
给出一个长度为 n n n 的序列,现在每次操作可以使某一位置的数减一(可以减为负数)。目标是求出使序列至少有 k k k 个数满足严格大于它旁边的两个数(第 1 1 1 个数只用严格大于第 2 2 2 个数,第 n n n 个数只用严格大于第 n − 1 n−1 n−1 个数)的最小操作数
现在求对于 k ∈ [ 1 , ⌈ n 2 ⌉ ] k \in [1,\lceil \frac n 2 \rceil] k∈[1,⌈2n⌉] 时的答案
1 ≤ n ≤ 5000 1 \leq n \leq 5000 1≤n≤5000
solution:
我们需要求出任意 k k k 下的最小操作数,那么很明显的一个方向就是设置一维记录满足要求的个数去做DP,这题的状态比较灵活,这里以其中一种为例作介绍
首先根据题意,想想为什么 k k k 的上界是 ⌈ n 2 ⌉ \lceil \frac n 2 \rceil ⌈2n⌉,因为严格的偏序关系在相邻两数之中至多只能有一个数字满足,那么最好情况就是隔一个满足一个。
那么明确了这一点,我们可以开始设置转移状态。
首先 f ( i , j ) f(i,j) f(i,j) 代表前 i i i 个数中有 j j j 个数满足关系,然而在想转移方程的时候我们发现这样没法保证偏序关系的合法性,并且由于我们不知道前面一个数有没有操作过,我们根本没法转移
那么我们只需要多设置一维,把之前的情况用状态描述清楚即可。
这里又有很多种设置方法,我们设 f ( i , j , k ) f(i,j,k) f(i,j,k) 代表前 i i i 个数中有 j j j 个数满足关系,并且用 k k k 来描述 a i a_i ai 和 a i − 1 a_{i-1} ai−1 的状态,具体的:
- 当 k = 0 k=0 k=0 时代表 a i − 1 a_{i-1} ai−1 与 a i a_i ai 都不满足
- 当 k = 1 k=1 k=1 时代表 a i a_i ai 满足, a i − 1 a_{i-1} ai−1 不满足
- 当 k = 2 k=2 k=2 时代表 a i − 1 a_{i-1} ai−1 满足, a i a_i ai 不满足
转移方程:
如果当前 k = 0 k=0 k=0,显然必须从 a i − 1 a_{i-1} ai−1 不满足的状态转移过来
f ( i , j , 0 ) = m i n { f ( i − 1 , j , 0 ) , f ( i − 1 , j , 2 ) } f(i,j,0)=min \{ f(i-1,j,0),f(i-1,j,2) \} f(i,j,0)=min{ f(i−1,j,0),f(i−1,j,2)}
如果当前 k = 1 k=1 k=1,那么也必须从 a i − 1 a_{i-1} ai−1 不满足条件的的状态转移过来,并且要使 a i − 1 a_{i-1} ai−1 的值严格小于 a i a_i ai,根据几种情况, a i − 1 a_{i-1} ai−1 的值肯定为了使 a i − 2 a_{i-2} ai−2 满足条件而减少,所以我们需要判断:
f ( i , j , 1 ) = m i n { f ( i − 1 , j − 1 , 0 ) + m a x ( 0 , a i − 1 − a i + 1 ) , f ( i − 1 , j − 1 , 2 ) + m a x ( 0 , m i n ( a i − 2 − 1 , a i − 1 ) − a i + 1 ) } f(i,j,1)=min \{ f(i-1,j-1,0)+max(0,a_{i-1}-a_i+1),f(i-1,j-1,2)+max(0,min(a_{i-2}-1,a_{i-1})-a_i+1) \} f(i,j,1)=min{ f(i−1,j−1,0)+max(0,ai−1−ai+1),f(i−1,j−1,2)+max(0,min(ai−2−1,ai−1)−ai+1)}
如果当前 k = 2 k=2 k=2,显然必须从 a i a_{i} ai 满足的状态转移过来
f ( i , j , 2 ) = f ( i − 1 , j , 1 ) + m a x ( 0 , a i − 1 − a i − 1 ) f(i,j,2)=f(i-1,j,1)+max(0,a_{i-1}-a_i-1) f(i,j,2)=f(i−1,j,1)+max(0,ai−1−ai−1)
综上,我们可以对于最后的 k k k,只需取 m i n { f ( n , k , 0 ) , f ( n , k , 1 ) , f ( n , k , 2 ) } min \{ f(n,k,0),f(n,k,1),f(n,k,2) \} min{ f(n,k,0),f(n,k,1),f(n,k,2)} 即可。
转移时可以先把 i = 1 i=1 i=1 时的情况手动转移,然后就不需要特判一些边界了。并且为了节省空间这题显然可以滚动数组,甚至不需要滚,可以省略一维,然后根据 k k k 的具体转移要求将 j j