博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【CF EDU59 E】 Vasya and Binary String (DP)
阅读量:4634 次
发布时间:2019-06-09

本文共 1386 字,大约阅读时间需要 4 分钟。

题意

给一串01串,对该串进行若干次操作,直到串为空

操作为:选择一段连续的0或者1,删除它,拼接前后两部分成为新串,得到价值为a[删除的长度](a为给定的数组)

思路

一个非常规的DP

考虑题目所给的操作,我们从中删除一段,再把前后拼接起来,如何设置状态?记录下断点的位置?不行,那样我们可能在其中插入很多断点,并且不便于转移

$...111000111...$

如果我们仅仅研究中间的子串$111000111$

我们删除中间的0,形成$111111$

再删除中间的1,这样我们其实可以看做原串是$000\underline{111}111$

也就是前面的1和后面的1其实是捆在一起的,这样按原来的操作,答案不会改变

设置状态:$dp[i][j][k]​$ 表示删除从i到j的子串,该子串前面捆绑了$k-1​$个与$s[i]​$相同的字符,能得到的最大价值

这样的话,考虑转移方式:

  1. 我们直接删除前面$k$个相等的字符,$dp[i][j][k] = a[k] + dp[i+1][j][1]$,因为捆绑的全消耗掉了所以后半部分是$K = 1$

  2. 我们从中删除一段,再把前后粘贴起来,这样的话,也就是上面的情况,我们需要把前面的和后面的捆绑起来,所以必须满足从中找到一个点$mid > i,s[i] = s[mid]$,这样的话$dp[i][j][k] = dp[i+1][mid-1][1] + dp[mid][j][k+1]$

    看这个式子,我们只捆绑的是第一个字符,因为我们可以多次进行这样的操作,使得捆绑的是任意的(这里不需要我们自己去构造,而是在求解过程中自然构造的)

所以最后的答案是$dp[1][n][1]$

由于这个转移比较骚,我们可以采用记忆化搜索

代码

#include
using namespace std;typedef long long ll;int n;char s[105];ll a[105];ll dp[105][105][105];ll DP(int be,int en,int pre) { if(be > en) return 0; if(dp[be][en][pre]) return dp[be][en][pre]; if(be == en) return dp[be][en][pre] = a[pre]; ll ans = a[pre] + DP(be+1,en,1); for(int mid = be+1;mid <= en;mid++) { if(s[mid] == s[be]) ans = max(ans,DP(be+1,mid-1,1) + DP(mid,en,pre+1)); } return dp[be][en][pre] = ans;} int main() { ios::sync_with_stdio(false); cin>>n; cin>>s+1; for(int i=1;i<=n;i++) cin>>a[i]; cout<
<

转载于:https://www.cnblogs.com/greenty1208/p/10331195.html

你可能感兴趣的文章
无敌简单快速的文件服务器sgfs
查看>>
Chapter 5 Blood Type——33
查看>>
从github clone文件: Failed to receive SOCKS4 connect request ack.
查看>>
英语学习Day1
查看>>
JavaScript
查看>>
Overload重載和Override重写的区别。Overloaded的方法是否可以改变返回值的类型?
查看>>
响应式面包屑菜单
查看>>
python实例31[文件夹清理]
查看>>
删除节点removeChild()
查看>>
Gearman 启动日志文件提示协议出错的BUG
查看>>
js中的this
查看>>
[转]深入理解linux内核list_head
查看>>
百度富文本编辑器的应用技巧---在一个页面中使用多个样式不同功能不同的编辑器...
查看>>
windows mysqldump 不成功 1049 1064 报错
查看>>
js call(),apply(),对象冒充,改变变量作用域
查看>>
查看符号表
查看>>
web安全测试-AppScan使用分享
查看>>
Javascipt数组去重的几种方式
查看>>
磁盘结构简介
查看>>
组织机构sql
查看>>