zoukankan      html  css  js  c++  java
  • DP做题笔记

    一些博客

    一个比较完整的总结

    带权二分

    决策单调性

    未来费用区间DP

    做题记录

    • [x] SCOI2010 股票交易

      (f[i][j]) 表示第 (i) 天拥有 (j) 张股票的最大收益,不难发现,每一天都不会即买入又卖出,于是就会有三种情况:

      1. 不买不卖:(f[i][j]=f[i-1][j])
      2. 买入:(f[i][j]=f[i-w-1][k]-AP_i(j-k)::(kge j-AS_i))
      3. 卖出:(f[i][j]=f[i-w-1][k]+BP_i(k-j)::(kle j+BS_i))

      其中,(k) 枚举的是第 (i-w-1) 天拥有的股票数。

      考虑如何优化,以买入为例:

      首先将式子变形,把与 (k) 有关的放在一起:

      [f[i][j]=(f[i-w-1][k]+AP_i imes k)-AP_i imes j::(kge j-AS_i) ]

      前半部分其实就是一个滑动窗口了,复杂度 (O(TMaxP))

      参考代码

    • [x] LuoguP2900 Land Acquisition G

      由于花费只与一组内的最长的长与宽有关,所以我们可以先按照长降序排序之后将有被包含关系(即长宽都小于别人)的矩形删去,廷尉他们是不会造成额外花费的。因此在剩下的矩形中,长都是降序,宽都是升序。

      (f[i][j]) 表示前 (i) 块地分为 (j) 组的最小代价,则有:

      [f[i][j]=min_{k<i}{f[k][j-1]+a_{k+1} imes b_i} ]

      (k)(x) 比选 (y) 更优,且 (x>y),那么:

      [f[x][j-1]+a_{x+1} imes b_i<f[y][j-1]+a_{y+1} imes b_i \frac{f[x][j-1]-f[y][j-1]}{a_{y+1}-a_{x+1}}le b_i ]

      于是我们得到了一个可以斜率优化的式子,由于 (b_i) 递增,所以维护一个下凸壳就可以了。

      参考代码

    • [x] HNOI2009 诗人小G

      这是一道决策单调性的题目,可是我并不会证。

      (f[i]) 表示前 (i) 句话的最小不协调度之和,可以得到:

      [f[i]=min_{j<i}{f[j]+|s_i-s_j-1-L|^{P}} ]

      其中,(s_i) 表示长度前缀和(包括空格),(-1) 是因为行末是不包括空格的。

      由于这个转移式具有决策单调性,所以我们使用二分栈(队列)来维护所有的决策点,因为决策单调,所以最优决策点一定是形如({1,1,2,2,2,3,4,4,cdots}) 这样的数列,对于栈中的任意两个点,都可以通过二分来找到一个临界点 (k),使得在 (k) 之前,通过前一个决策点更优,在 (k) 之后,通过后一个决策点更优。

      当我们枚举到 (i) 这个位置时,对于队首,只要栈顶与下一个点的临界点小于等于 (i),那么弹掉队首,对于队尾,如果倒数第二个点与队尾的临界点大于等于队尾与 (i) 的临界点,即这两对点所“负责”的区域发生了重叠,那么弹掉队尾,最后把 (i) 入队。而每次的最优决策点即为队首。

      输出有亿点毒瘤……

      参考代码

    • [x] NOI2005 瑰丽华尔兹

      一道挺好的单调队列优化DP

      (f[k][i][j]) 表示在 (k) 时段,走到 ((i,j)) 能获得的最大距离。朴素的DP方程是:

      [f[k][i][j]=max{f[k-1][i][j],f[k][i'][j']+dis(i,j,i',j')} ]

      其中 ((i',j')) 是一个在 (k) 时段内可以到达 ((i,j)) 的位置。

      可以用单调队列优化掉 (j) 这一维。

      几点注意:

      • 遇到无法到达的点时,清空队列。
      • 四个方向分开讨论(因为他们的起点不同)。
      • 先更新队尾再更新DP值,因为更新队尾元素时要用到上一次的DP值。
      • 最开始将DP数组赋为负无穷(起点除外)。

      参考代码

    • [x] POI2014 PTA-Little Bird

      (f[i]) 表示到达第 (i) 课树时的最小代价,DP方程为:

      [f[i]=min_{j<i}{f[j]+[h_jle h_i]}::(i-jle k) ]

      注意到一个性质:当DP值相同时,用高度小的树转移必然更优,当DP值不同时,用DP值小的树转移更优(因为树高最多使DP值(+1))。

      于是就可以单调队列优化了。

    • [x] POI2011 Lightning Conductor

      易得 (p[i]=max{a_j+sqrt{|i-j|}}-a_i)

      先不管最后的 (a[i]),打表可知,前半部分的转移是有决策单调性的。于是我们可以用队列模拟二分栈来解决这一问题。值得注意的是,为了便于计算,我们先假设所有的 (i) 都由一个小于自己的 (j) 转移过来,也就是说先不管绝对值。为了得到最终的答案,我们还需要把数列反转,再求一遍并取max。

      参考代码

    • [x] SDOI2016 征途

      一道带权二分+斜率优化的题目。

      先将题目中要求的式子转化一下:

      [egin{split} s^2 imes m^2&=msum_{i=1}^{m}{(overline x-x_i)^2} \&=mcdot[sum_{i=1}^{m}{x_i^2+moverline x^2-2overline xsum_{i=1}^{m}{x_i}}] \&=msum_{i=1}^{m}{x_i^2}-(sum_{i=1}^{m}{x_i})^2 end{split} ]

      于是问题转化为了使得 (sum_{i=1}^{m}{x_i^2}) 最小。

      (f[i][j]) 表示第 (j) 天走完 (i) 段时上式的最小值。可以得到:

      [egin{split} f[i][j]&=min_{k<i}{f[k][j-1]+(s_i-s_k)^2} \&=min_{k<i}{f[k][j-1]+s_k^2-2s_is_j}+s_i^2 end{split} ]

      其实推到这里已经可以斜率优化 (O(mn)) 通过此题,但还可以优化。

      可以发现 (f) 值随着划分次数的增加而减少,因此我们可以采用带权二分的方法去掉 (j) 这一维,通过二分分段的权值来使段数逼近 (m)。这样做的复杂度是(O(nlogsum x_i)) 的。

      参考代码

    • [x] LuoguP2619 Tree

      这题虽然不用DP,但是需要带权二分,所以也放在这里。

      具体思路是二分给白边附加的权值,再求最小生成树,当选择的白边数量为 (need) 时输出答案即可。

      有一些比较恶心的地方:排序的时候要在权值相等时白边优先,二分时应该是 (lle r) 而不是 (<)……

      参考代码

    • [x] IOI2000 邮局

      四边形优化DP。

      (f[i][j]) 表示前 (i) 个村庄建 (j) 个邮局的最小距离。可以得到:

      [f[i][j]=min{f[k][j-1]+w[k+1][i]} ]

      其中 (w[i][j]) 表示在 ([i,j]) 中建邮局的最小距离和,它如何计算呢?

      首先有一个结论:若区间长度为奇数,那么将邮局建在中位数处距离和最小;若为偶数,那么建在中间两个之间的任意位置都一样。

      所以,我们可以分类讨论:

      • 若区间长度为奇数:中位数在 (frac{i+j}{2}) 处,相较于 ([i,j-1]),可以认为中位数没有变化(因为总距离不变),所以总和增加了 (d[j]-d[frac{i+j}{2}])
      • 若长度为偶数也可以用同样的思路得出同样的结论。

      综上,我们得到了递推式:

      [w[i][j]=w[i][j-1]+d[j]-d[frac{i+j}{2}] ]

      然后就是四边形优化的套路了,外层正序枚举 (j),内层逆序枚举 (i)(k) 的范围为 ([s[i][j-1],s[i+1][j]])。( (s) 表示最优决策点)

      参考代码

    • [x] 六省联考2017 组合数问题

      考虑给出式子的组合意义,相当于从 (nk) 个不同物品中选出 (t) 个,且满足 $tmod k=r $ 的方案数。我们设 (f[i][j]) 表示当前考虑到第 (i) 个物品,所选数量 (mod k)(j) 的方案数,遂于每个物品有选与不选两种选择,所以:

      [f[i][j]=f[i-1][j]+f[i-1][j-1] ]

      发现每一次转移都只与 (f[i-1]) 有关,所以可以矩阵加速,转移矩阵为:

      [egin{bmatrix} f_{nk,0}\ f_{nk,1}\ f_{nk,2}\ vdots \ f_{nk,k}\ end{bmatrix} = egin{bmatrix} 1 & 0 & cdots & 0 & 1 \ 1 & 1 & 0 & cdots & 0 \ 0 & 1 & 1 & cdots & 0 \ vdots & ddots & ddots & ddots & vdots \ 0 & 0 & cdots & 1 & 1 \ end{bmatrix}^{nk} egin{bmatrix} 1\ 0\ 0\ vdots \ 0\ end{bmatrix} ]

      矩阵快速幂即可。

      参考代码

    • [x] SDOI2008 Sue的小球

      未来费用提前计算的区间DP。

      (f[i][j][0/1]) 表示处理完区间 ([i,j]) 之后在左/右端点时的最小代价,最终答案为 (sum{y}-min{f[1][n][0],f[1][n][1]})

      当处理完后在左端点时,可以从 (f[i+1][j][0/1]) 转移过来,即:

      [min egin{cases} f[i+1][j][0]+(s_i+s_n-s_j)(b_{i+1}.x-b_{i}.x) \f[i+1][j][1]+(s_i+s_n-s_j)(b_j.x-b_i.x) end{cases} ]

      在右端点时同理:

      [min egin{cases} f[i][j-1][0]+(s_{i-1}+s_n-s_{j-1})(b_{j}.x-b_{i}.x) \f[i][j-1][1]+(s_{i-1}+s_n-s_{j-1})(b_j.x-b_{j-1}.x) end{cases} ]

      老实说,这类问题的思路基本都是这样。

      参考代码

    • [x] UVA1336 修筑长城

      跟上一题几乎一毛一样,注意亿下输出。

      参考代码

    • [x] UVA1628 送披萨

      与上一题不同的是,本题中可以选择跳过某些不利的点,对此,我们的处理方法是:加维。

      增加一维表示还需要送的人数,每次转移时分别往两边枚举出一个点,钦定当前端点到该点的这一段跳过,这样就可以处理跳过点的情况了。

      用记搜实现会比较方便。

      参考代码

    • [x] CF1107E Vasya and Binary String

      消消乐问题。

      (f[i]) 表示 (i) 个一样的连在一起的元素被消去后得到的最大分数,可以用完全背包处理。

      然后将连续的一段相同元素合并成一个点,原序列就变成了若干个黑白交错的点,记点 (i) 中的元素个数为 (sz[i])

      (g[l][r][k]) 表示现在要消玩 ([l,r]) 这一段点,其中点 $r $ 后面还吊着 (k) 个与 (r) 相同的元素,那么 (r) 可以选择单独消或者与前面的元素一起消。

      单独消:(g[l][r-1][0]+f[k+sz[r]])

      一起消:(g[i+1][r-1][0]+g[l][i][k+sz[r]]),其中 (i) 是一个颜色与 (r) 相同的点。

      同样可以记忆化搜索实现。

      参考代码

    • [x] LuoguP1220 关路灯

      又是一道未来费用提前计算的题,方法同上。

      参考代码

    • [x] HDU2829 炸铁路

      四边形优化DP。

      (f[i][j]) 表示前 (i) 条铁路炸成 (j) 段的最小花费,则:

      [f[i][j]=min{f[k][j-1]+w[k+1][i]} ]

      (w[i][j]) 可以递推计算:

      [w[i][j]=w[i][j-1]+a[j] imes(sum[j-1]-sum[i-1]) ]

      其中 (sum[i]) 表示前缀和。

      参考代码

    • [x] CF634C Levels and Regions

      概率期望与DP的结合。

      每一关一小时通过概率为 (frac{t_i}{sum_{x=l_j}^{i}{t_x}}),故通过这一关的期望时间为 (frac{sum_{x=l_j}^{i}{t_x}}{t_i})

      (w(l,r)) 表示通过 ([l,r]) 这一段区间中的关的期望时间,那么:

      [egin{split} w(l,r)&=sum_{x=l}^{r}{frac{s_x-s_{l-1}}{t_x}} \&=sum_{x=l}^{r}{frac{s_x}{t_x}}-s_{l-1}sum_{x=l}^{r}{frac{1}{t_x}} end{split} ]

      其中 (s_i) 表示 (t) 的前缀和。

      (s_i) 记作 (s0_i),将 (sum_{x=1}^{i}{frac{s _x}{t_x}}) 记作 (s1_i)(sum_{x=1}^{i}) 记作 (s2_i),那么:

      [w(l,r)=s1_r-s1_{l-1}-s0_{l-1}(s2_r-s2_{l-1}) ]

      (f[i][j]) 表示前 (i) 关分为 (j) 个等级的最短期望时间,则:

      [f[i][j]=min{f[k][j-1]+w(k+1,i)} ]

      (w) 带入后就可以得到可以斜率优化的式子了。

      参考代码

    • [x] ICPC2016 WF

      最短路+DP。

      基本的思路并不难,先处理出总部到各个分部与各个分部到总部的最短路,然后四边形优化DP即可。但是有一点要注意:在处理出每一点往返总部距离之后应将它们排序之后再DP。

      因为每个点对答案的贡献只与其所在集合大小有关,因此,权值小的点应尽量处在一个相对较大的集合中,即在所有集合中,最大的那一个中的点权和应最小,因此要把最小的几个点放入第一个(最大的)集合。所以,对点权排序之后可以让答案最优。

      参考代码

    • [x] SP3734 PERIODNI - Periodni

      笛卡尔树+DP

      对原序列建立笛卡尔树,节点 (u) 的意义就是一个高度为 (h[fa]-h[u]) 的横着的极大矩形。不难发现,在两个儿子中放棋子是互不影响的,所以考虑树形DP。

      (f[i][j]) 表示第 (i) 个节点为根的子树中放了 (j) 个棋子的方案数。

      先合并左右子树的答案:

      [f[i][j]=sum_{kle j}{f[v][j-k]cdot f[i][k]} ]

      其中 (v) 表示 (i) 的儿子。

      然后还要求对于 (i) 节点表示的矩形中放棋子的方案:

      [f[i][j]=sum_{kle j}{f[i][j-k]cdot k!cdot C^k_hcdot C^k_{w-j_k}} ]

      其中,(h,w) 分别表示长和宽。

      参考代码

    • [x] CF939F Cutlet

      (f[i][j]) 表示到时间 (r_i) 时,现在未烤的那一面烤了 (j) 分钟的方案数,对于时间段 ([l_i,r_i]) 就会有如下转移:

      • 不翻面:(f[i-1][j])
      • 翻一次:(min {f[i-1][r_i-j-k]}+1),其中,(k) 表示当前烤了的这一面在这段时间内烤的时间。
      • 翻两次:(min{f[i-1[j-k]}+2),其中,(k) 表示当前没烤的那一面在这段时间内烤的时间。

      需要用单调队列优化,枚举的是最优决策点 (r_i-j-k)(j-k),前者随 (j) 的增大而减小,所以要逆推,而后者要顺推。

      还能用滚动数组优化掉 (i) 那一维。

      参考代码

  • 相关阅读:
    C#获取配置文件中的文件数据
    wpf MVVMLight的DataGrid绑定数据
    扫码支付自动跳转,可以使用第三方网站实现扫码二维码付款然后跳转到想要的页面展示想要内容或者是解压码或者是某个资源的下载页呢 具体步骤(我以你上传一个压缩包到某种网盘或者可以下载的地址等让人付费解压为例):
    oracle数据库如何创建用户以及分配权限
    ORA-12547: TNS: 丢失连接
    springmvc中applicationapplicationContext头部代码
    No mapping found for HTTP request with URI
    在Navicat新建用户
    myeclipse 项目引入 com.sun.image.codec.jpeg 的api报错解决方法
    java.lang.NullPointerException at org.apache.jsp.**_jsp.jspInit(**_jsp.java)tomcat启动异常解决方法
  • 原文地址:https://www.cnblogs.com/whenc/p/14421308.html
Copyright © 2011-2022 走看看