DP提高专项1题解

主要讲一下每一题的做法以及思考方式。

感觉难度薇 \(T1-T3-T2\) 。但是都不算难。

\(T1\)

题目描述

Jimmy 最近迷上了一款叫做方块消除的游戏。游戏规则如下:\(n\) 个带颜色方格排成一列,相同颜色的方块连成一个区域(如果两个相邻方块颜色相同,则这两个方块属于同一区域)。为简化题目,将连起来的同一颜色方块的数目用一个数表示。

例如,9 122233331 表示为

4
1 2 3 1
1 3 4 1

游戏时,你可以任选一个区域消去。设这个区域包含的方块数为 \(x\),则将得到 \(x^2\) 个分值。方块消去之后,其余的方块就会竖直落到底部或其他方块上。而且当有一列方块被完全消去时,其右边的所有方块就会向左移一格。Jimmy 希望你能找出得最高分的最佳方案,你能帮助他吗?

第一行包含一个整数 \(m\)\(1 \le m \le 50\)),表示同颜色方块区域的数目。
第二行包含 \(m\) 个数,表示每个区域的颜色(\(1\)\(m\) 之间的整数)。
第三行包含 \(m\) 个数,表示每个区域包含的方块数(\(1\)\(20\) 之间的整数)。

思路点拨

挺简单的一题。考虑到本题从序列中间开始操作会得到不同的结果,所以不可以使用类似于子序列提取的线性dp,而是考虑区间dp。

我们比较头疼的是,在消除完之后右边的方块会挪过来,所以我们可以在状态中体现这一点。我们定义 \(f_{l,r,k}\) 表示是目前考虑了区间 \(l,r\) 的方格,右端点右边接了 \(k\) 个与之颜色相同过的方块的最大价值。

转移分两类讨论:

  • 把右边炸了!

\[f_{l,r,k}=f_{l,r-1,0}+(num[r]+k)^2 \]

  • 考虑炸掉中间一段,然后右边的 \((num[r]+k)\) 移到左边去(要求左边与右边颜色相同)

\[f_{l,r,k}=f_{l,mid,num[r]+k}+f_{mid+1,r-1,0} \]

别的不需要多多考虑,因为我们最为简单的方式就是从左到右依次炸掉,我们不论怎么操作,答案不会劣于这个。所以我们只需要考虑让颜色相同的尽量在一起炸掉。

时间复杂度 \(O(n^4)\)

代码很短,不放了。

\(T3\)

题目描述

现在有 \(n\) 个元素,构成一颗二叉排序树。还知道这颗二叉排序树父子之间权值不互质,问是否存在这样的树?

$n \leqslant 700 $ 。

思路点拨

二叉排序树的性质:中序遍历是有序的。我们考虑对原序列排序之后区间 \(dp\) ,按照中序遍历 \(dp\)

因为需要父子之间权值互质,所以我们在状态里记录一下根。设 \(f_{l,r,k}\) 表示考虑到区间 \(l,r\) ,根位 \(k\) 是否可以满足条件。那么

\[f_{i,j,k}=(\sum_{i \leqslant r <k} f_{i,k-1,r}[\gcd(a_k,a_r)>1])(\sum_{k< r \leqslant j} f_{k+1,j,r}[\gcd(a_k,a_r)>1]) \]

时间复杂度 \(O(n^4)\) ,不可以通过。

考虑优化,我们发现我们做了一个十分智障的操作。我们在状态里面记录根的目的就是为了保证根与根的父亲不互质,但是没有必要将根表示出来。因为对于区间 \([l,r]\) 而言,它的根的父亲无非就是 \(l-1,r+1\) 两种。所以我们可以更改一下状态:

\(f_{l,r}\) 表示考虑到区间 \([l,r]\) ,根的父亲是 \(l-1\) 的方案。

\(g_{l,r}\) 表示考虑到区间 \([l,r]\) ,根的父亲是 \(r+1\) 的方案。

转移方式几乎不变,枚举一个根(\(vis\) 数组表示是否互质):

	for(int len=2;len<=n;len++)
		for(int l=1,r=len;r<=n;l++,r++)
			for(int mid=l;mid<=r;mid++){
				if(vis[mid][r+1]) f[l][r]|=(f[l][mid-1]&g[mid+1][r]);
				if(vis[mid][l-1]) g[l][r]|=(f[l][mid-1]&g[mid+1][r]);
			}

时间复杂度 \(O(n^3)\)

\(T2\)

题目描述

Dreamoon 有一个字符串 \(s\) 和一个模式串 \(p\),他会先从 \(s\) 中删除恰好 \(x\) 个字符来产生一个新的字符串 \(s'\)。然后他会计算 \(occ(s',p)\),即从 \(s'\) 中能找到的等于 \(p\) 的不相交的子串数量的最大值。他想让 \(occ(s',p)\) 的值尽可能大。

更形式地说,让我们用 \(ans(x)\) 表示所有可以从 \(s\) 中删去恰好 \(x\) 个字符得到的 \(s'\)\(occ(s',p)\) 的最大值。Dreamoon 想要知道对于所有的 \(x\) \((0 \leq x \leq |s|)\)\(ans(x)\) 的值。

\(|s| \leqslant 2000, |p| \leqslant 500\)

思路点拨

本场比赛最有思维含量的一题,比较靠设状态。

看到题目,这题挺 \(\text{KMP}\) 的。我们定义状态 \(f_{i,j,k}\) 表示目前考虑到下标 \(i\) ,删除了 \(j\) 个字符,目前 \(\text{KMP}\) 的失配指针在 \(p\) 字符串的下标 \(k\) 时,以及匹配的 \(p\) 的数量的最大值。

转移可以刷表。对于 \(f_{i,j,k}\) 而言,我们考虑 \(i+1\) 的状态:

  • 删了

  • 不删,此时维护 \(\text{KMP}\) 的失配指针。

特别好想,时间 \(O(|s|^2|p|)\) ,不可以通过。

发现,上面这个 \(dp\) 因为依赖了 \(\text{KMP}\) 这个类似于自动机的东西,所以我们的第三维无法优化掉,所以我们换思考方向,将 \(p\) 作为一个整体去思考。

那么我们又可以得出如下状态:

\(f_{l,r}\) 表示区间 \(l,r\) 是否可以提取出子序列 \(p\) ?如果可以,那么 \(f_{l,r}=r-l+1-|p|\) ,如果不可以 \(f_{l,r}=inf\) 。这是很好预处理,不讲。

\(dp_{i,j}\) 表示考虑到下标 \(i\) ,删除了 \(j\) 个字符的情况下,匹配 \(p\) 的最大值。转移比较明了:

\[dp_{i,j}=\max\{dp_{mid,j-f_{mid+1,i}}+1\} \]

时间复杂度 \(O(|s|^3)\) 。虽然比较劣,但是我们发现状态有优化的空间。

我们假设,\(g_i\) 表示从下标 \(i\) 往左边找,能够平凑处 \(|p|\) 这个子序列的最大下标。从 \(g_i\) 开始,我们的 \(f\) 数组 \(+1\)\(g_i\) 之前的东东我们可删可不删,而只有在 \([g_i,i]\) 之间的元素我们必须删除,我们可以简单改一下状态。

\(dp_{i,j}\) 表示考虑到下标 \(i\)至少 删除了 \(j\) 个字符的情况下,匹配 \(p\) 的最大值。转移比较明了:

\[dp_{i,j}=\max\{dp_{g_i-1,j-f_{g_i,i}}+1,dp_{i-1,j},dp_{i-1,j-1}\} \]

大概就是这样,优势在于决策点减少了。具体细节不讲。

时间复杂度 \(O(|s|(|s|+|p|))\)

posted @ 2023-10-05 15:26  Diavolo-Kuang  阅读(7)  评论(0编辑  收藏  举报