区间dp

P1880 [NOI1995] 石子合并(破环成链+石子合并类套路)

题目

在一个圆形操场的四周摆放 \(N\) 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 \(2\) 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 \(N\) 堆石子合并成 \(1\) 堆的最小得分和最大得分。

\(1\leq N\leq 100\)\(0\leq a_i\leq 20\)

题解

环形的序列,那么断开环,倍长序列去做

\(f[l][r]\) 表示合并区间 \([l,r]\) 中的所有石子所能带来的最大收益,\(sum[l][r]\) 表示 \([l,r]\) 中石子个数的和,转移方程如下

\[f[l][r]=\max_{l\le k\le r}\lbrace f[l][k]+f[k+1][r]+sum[l][r]\rbrace \]

时间复杂度为 \(\mathcal O(n^3)\),可以使用四边形不等式优化到 \(\mathcal{O} (n^2)\) ,但这不是提高组的考察范围

HDU 4283 You Are the One (栈的性质+石子合并类套路)

题目

有一个长为 \(N~(N\le 100)\) 的队列,第 \(i\) 个人有一个愤怒值 \(D_i\),如果他是第 \(K\) 个上场,不开心指数就为 \((K-1)\cdot D\)。但是边上有一个小黑屋(后进先出,当成个堆栈),可以一定程度上调整上场顺序,使不开心指数最小

题解

考虑栈的性质,第 \(i\) 个元素入栈,如果它最终的位置是在 \(k\),那么 \(i\)\(k\) 这一段中不可能有 \(k\) 位置后的数出现。因此把问题 \([l,r]\) 分为子问题 \([l+1,k]\),\([k+1,r]\),直接转移即可

时间复杂度 \(\mathcal{O}(N^3)\)

P1005 [NOIP2007 提高组] 矩阵取数游戏 (取两端套路)

题目

题解

首先一轮一轮的考虑是困难的,所以我们一行一行的考虑

这样原问题可以转化对每一行确定选数的顺序

那么就可以通过区间dp转移了,假设要选完 \([l,r]\) 中的数,由于每次只能取两边的数,那么就从 \([l,r-1]\times 2\) 或者 \([l+1,r]\times 2\) 转移而来

时间复杂度 \(\mathcal{O}(mn^2)\)

P3205 [HNOI2010]合唱队 (取两端套路+增加维数)

题目

题解

考虑对理想队形进行区间dp,假设此时考虑排成区间 \([i,j]\) 队形的方案数,但是如果采取普通的 \(f[i][j]\) 的二维dp考虑,我们发现我们无法转移

原因是我们dp的状态中缺少上一次的值放在了那里这一个信息,所以将状态修改为 \(f[i][j][0/1]\) 表示排成区间 \([i,j]\) 中的队形且第 \(i\) 个人在左端/第 \(j\) 个人在右端时的方案数

转移如下

if(a[i]<a[i+1])f[i][j][0]+=f[i+1][j][0];
if(a[i]<a[j])f[i][j][0]+=f[i+1][j][1];
if(a[j]>a[i])f[i][j][1]+=f[i][j-1][0];
if(a[j]>a[j-1])f[i][j][1]+=f[i][j-1][1];

初始状态注意把所有的数都当成从左边进来的,不然会算重,时间复杂度 \(\mathcal{O}(n^2)\)

P1220 关路灯 (提前计算贡献)

题目

题解

首先考虑如果经过一个灯而不关掉它显然是不优的,所以每次关掉的灯一定是一段连续的区间

于是设 \(f[i][j][0/1]\) 表示关掉了区间 \([i,j]\) 中所有的灯之后,身处最左端/右端时的所有的灯总的功耗和

那么就有转移

f[l][r][0]=min(f[l+1][r][0]+(p[l+1]-p[l])*(pre[l]+pre[n]-pre[r]),f[l+1][r][1]+(p[r]-p[l])*(pre[l]+pre[n]-pre[r]));
f[l][r][1]=min(f[l][r-1][1]+(p[r]-p[r-1])*(pre[l-1]+pre[n]-pre[r-1]),f[l][r-1][0]+(p[r]-p[l])*(pre[l-1]+pre[n]-pre[r-1]));

其实这本质是个贪心, \(\text{dfs}\) 也是可以做的

时间复杂度 \(\mathcal{O}(n^2)\)

P4170 [CQOI2007]涂色 (涂色类套路)

题目

给定一个长度为 \(n~(n\le 500)\) 的木板,初始没有颜色。

我们现在要在上面涂色,每次涂色必须涂连续的一段区间且可以覆盖之前涂过的颜色

问使初始木板变成目标颜色的最小操作次数

题解

\(f[i][j]\) 表示将区间 \([i,j]\) 中的位置变成目标颜色的方案数

那么考虑分类讨论

  • \(i=j\),则有 \(f[i][j]=1\)

  • \(\text{col}[i]=text{col}[j]\) ,那么我们直接在端点处染色即可

  • \(\text{col}[i]\neq \text{col}[j]\) ,那么我们就枚举一个分界点,左右两边涂不同的颜色

状态转移如下

if(l==r) f[l][r]=1
else if(s[l]==s[r]) f[l][r]=min(f[l+1][r],f[l][r-1]);
else if(s[l]!=s[r]) for(int k=l;k<r;k++) f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);

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

HDU 2476 String painter (分步涂色)

题目

给定两个初始串 \(\text{a},\text{b}\) ,求将 \(\text{a}\) 区间染色成 \(\text{b}\) 的最小步数

\(|a|=|b|\le 500\)

题解

首先一个朴素的思路是直接设 \(f[i][j]\) 表示将 \(\text{a}\) 中的 \([l,r]\) 染成 \(\text{b}\) 的最小步数

但是你要分十万种情况讨论,理论可行,但不可做

所以我们考虑这样一个过程,我们可以先计算从无色串到 \(\text{b}\) 的最小步数,这就是“Luogu P4170 [CQOI2007]涂色”,然后我们对 \(\text{a}\) 进行一个dp求出它那些位置需要染色,假设我们求出无色串染色区间 \([l,r]\) 染成 \(\text{b}\) 的最小次数为 \(f[l][r]\)

考虑如何对 \(a\) 序列进行dp,设 \(g[i]\) 表示考虑将 \(\text{a}\) 的前 \(i\) 位染色至 \(\text{b}\) 的最小的方案数,考虑如何进行转移,假设当前考虑到第 \(i\)

  • 如果 \(\text{a}[i]=\text{b}[i]\) ,那么 \(g[i]=g[i-1]\) 无需染色
  • 如果 \(\text{a}[i]\neq \text{b}[i]\) ,那么我们枚举染色的分界点 \(j\),转移方程为

\[g[i]=\min_{1\le j\le i-1}g[j]+f[j+1][i] \]

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

P7914 [CSP-S 2021] 括号序列(通过增维实现对不同情况的分类讨论)

题目

题解

首先,朴素的思路是设 \(f[i][j]\) 表示区间 \([l,r]\) 中合法的超级括号序列的数量,但是我们注意到题目中有“连续的 \(*\) 不超过 \(k\) 个”这一个条件,所以我们记录的这个状态记录的信息不够,所以考虑增维

\(f[i][j][p],p\in [0,5]\) , \(\text{A}\) 表示左右两边都是括号且这两个括号不匹配的串,其中

  • \(p=0\) 表示全是 \(*\) 的情况
  • \(p=1\) 表示 \((\text{A})\) 的情况
  • \(p=2\) 表示 \(\text{AS}\) 的情况
  • \(p=3\) 表示 \(\text{A}\) 的情况,注意该状态包含 \(p=1\) 的状态
  • \(p=4\) 表示 \(\text{SA}\) 的情况
  • \(p=5\) 表示 \(\text{SAS}\) 的情况,注意该状态包含 \(p=0\) 的状态

下面我们来考虑转移,思路就是在已有的 \(2,3,4,5\) 后边接上 \(0,1\) 这两个基本单位来转移

  • \(p=0\) 时,对 \(\text{len}\) 进行一个特判即可
  • \(p=1\) 时,如果当前区间 \([l,r]\) 的左右端点不匹配则为 \(0\) ,否则注意一下转移时不能有 \((SAS)\) 的情况,于是转移为

\[f[l][r][1]=f[l+1][r-1][0]+f[l+1][r-1][2]+f[l+1][r-1][3]+f[l+1][r-1][4]; \]

  • \(p=2\) 时,我们就是要拿 \(\text{A}\) 拼上 \(\text{S}\) ,这里不拿 \(\text{AS}\)\(\text{S}\) 是为了满足长度不超过 \(k\) 的方案数,于是转移如下

\[f[l][r][2]=\sum_{i=l}^{r-1}f[l][i][3]\times f[i+1][r][0] \]

  • \(p=3\) 时,我们可以通过 \(\text{AS}\) 拼上 \(\text{(A)}\) 或者 \(\text{A}\) 拼上 \(\text{(A)}\) ,注意加上 \(p=1\) 的情况

\[f[l][r][3]=\sum_{i=1}^{r-1}(f[l][i][2]+f[l][i][3])\times f[i+1][r][1]+f[l][r][1] \]

  • \(p=4\) 时,我们就是要找开头为 \(*\) 的即 \(\text{SA},\text{SAS}\) 的后面拼接 \((A)\)

\[f[l][r][4]=\sum_{i=1}^{r-1}(f[l][i][4]+f[l][i][5])\times f[i+1][r][1] \]

  • \(p=5\) 时,我们就是要找开头为 \(*\) 的即 \(\text{SA}\) 的后面拼接 \(S\) ,另外别忘了还有 \(\text{S}\)

\[f[l][r][5]=\sum_{i=1}^{r-1}f[l][i][4]\times f[i+1][r][0]+f[l][r][0] \]

答案必须为首尾都是括号序列.所以就为 \(f[1][n][3]\)

这样dp的时间复杂度为 \(\mathcal{O}(n^3)\)

posted on 2023-07-24 19:55  star_road_xyz  阅读(13)  评论(0编辑  收藏  举报

导航