Codeforces 1107E (Vasya and Binary String) (记忆化,DP + DP)
题意:给你一个长度为n的01串,和一个数组a,你可以每次选择消除一段数字相同的01串,假设消除的长度为len,那么收益为a[len],问最大的收益是多少?
思路:前两天刚做了POJ 1390,和此题很相似:POJ 1390 。我们甚至可以直接套用这个题的状态转移方程。仍然先把01串预处理一下,把相邻的并且数字相同的位合并成一个块。这样,01串就变成了若干个相邻的01块了。
设dp[i][j][k]为处理第i个块到第j个块,并且后面有k个位和第j个块颜色相同,设f[i]为消除长度为i的串的最大收益,那么状态转移方程可以这样写:
1:先把后面相同的合并了:dp[i][j][k] = max(dp[i][j][k], dp[i][j - 1][0] + f[第j个块的位的个数 + k]。
2:与前面的颜色相同的块合并(假设块j与块p颜色相同):dp[i][j][k] = max(dp[i][j][k], dp[i][p][k + 第j个块的位的个数] + dp[p + 1][j - 1][0]);
现在唯一的问题f数组怎么求?很明显此题并不是一次消除的长度越长越好,多次消除短的串可能获得更高的收益。我们可以思考一下,f[i]肯定是把长度i拆成1份,2份,......i份中收益最大的情况。
设re[i][j]为把长度j拆成i份获得的最大收益,我们可以暴力枚举第i份的长度是多少(假设是k),然后继续递归去求得把j - k拆成i - 1份的最优值来更新当前状态。那么f[i]就是re[1][i],re[2][i].....re[i][i]中的最优情况。
dp和re数组我们都可以记忆化,可以大幅度提高效率,31ms水过。。。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL dp[110][110][110];
bool v[110][110][110], v1[110][110];
LL f[110], b[110];
LL re[110][110]; struct node{
int flag, cnt;
};
node a[110]; LL get_f(int tot, int n) {
if(v1[tot][n]) return re[tot][n];
if(tot == 1) {
v1[tot][n] = 1;
return re[tot][n] = f[n];
}
else {
LL ans = 0;
for (int i = 1; i <= n - tot + 1; i++) {
ans = max(ans, f[i] + get_f(tot - 1, n - i));
}
v1[tot][n] = 1;
return re[tot][n] = ans;
}
} int cal(int n) {
LL ans = 0;
f[n] = b[n];
for (int i = 1; i <= n; i++) {
ans = max(ans, get_f(i, n));
}
f[n] = ans;
} LL solve(int l, int r, int x) {
if(v[l][r][x]) return dp[l][r][x];
if(l >= r) return f[a[r].cnt + x];
LL ans = solve(l, r - 1, 0) + f[a[r].cnt + x];
for (int i = l; i < r; i++) {
if(a[i].flag == a[r].flag) {
ans = max(ans, solve(l, i, a[r].cnt + x) + solve(i + 1, r - 1, 0));
}
}
v[l][r][x] = 1;
return dp[l][r][x] = ans;
} int main() {
int n;
char s[210];
scanf("%d", &n);
scanf("%s", s + 1);
int now_flag = -1, now = 0, tot = 0;
for (int i = 1; i <= n; i++) {
if(s[i] - '0' != now_flag) {
a[++tot].flag = s[i] -'0';
a[tot].cnt = 1;
now_flag = s[i] - '0';
} else {
a[tot].cnt++;
}
}
for (int i = 1; i <= n; i++) {
scanf("%lld", &b[i]);
}
for (int i = 1; i <= n; i++)
cal(i);
printf("%lld\n", solve(1, tot, 0));
}
Codeforces 1107E (Vasya and Binary String) (记忆化,DP + DP)的更多相关文章
- Codeforces1107E Vasya and Binary String 记忆化dp
Codeforces1107E 记忆化dp E. Vasya and Binary String Description: Vasya has a string \(s\) of length \(n ...
- Codeforces 1107 E - Vasya and Binary String
E - Vasya and Binary String 思路:区间dp + 记忆化搜索 转移方程看上一篇博客. 代码: #pragma GCC optimize(2) #pragma GCC opti ...
- CF 1107 E. Vasya and Binary String
E. Vasya and Binary String 链接 分析: 对于长度为x的一段序列,我们可以dp出消除的过程的最优方案,背包即可. 然后区间dp,可以先合并完所有的点,即没相同的一段区间合并为 ...
- HUD 1501 Zipper(记忆化 or DP)
Problem Description Given three strings, you are to determine whether the third string can be formed ...
- HDU1978How Many Ways 记忆化dfs+dp
/*记忆化dfs+dp dp[i][j]代表达到这个点的所有路的条数,那么所有到达终点的路的总数就是这dp[1][1]加上所有他所能到达的点的 所有路的总数 */ #include<stdio. ...
- 记忆化搜索(DP+DFS) URAL 1183 Brackets Sequence
题目传送门 /* 记忆化搜索(DP+DFS):dp[i][j] 表示第i到第j个字符,最少要加多少个括号 dp[x][x] = 1 一定要加一个括号:dp[x][y] = 0, x > y; 当 ...
- Vasya and Binary String(来自codeforces
题目大意: 给定一个0/1字符串,每次你可以将此字符串中一段连续的任意长度的0/1子串消除掉,注意每次消除的子串中只能有0或者1一种字符,消除掉一串长度为i的0/1字符串会得到a[i]的收益,问将这个 ...
- codeforces 284 D. Cow Program(记忆化搜索)
题目链接:http://codeforces.com/contest/284/problem/D 题意:给出n个数,奇数次操作x,y都加上a[x],偶数次操作y加上a[x],x减去a[x],走出了范围 ...
- Codeforces 294B Shaass and Bookshelf(记忆化搜索)
题目 记忆化搜索(深搜+记录状态) 感谢JLGG //记忆话搜索 //一本书2中状态,竖着放或者横着放 //初始先都竖着放,然后从左边往右边扫 #include<stdio.h> #inc ...
随机推荐
- IntelliJ IDEA创建Maven+SSM+Tomcat+Git项目【全程详解】
记录一下整个创建项目的过程,其中包括: Maven 项目创建: SSM配置文件: Tomcat配置: Git配置: Git忽略文件Ignore配置: 图文讲解,通俗易懂,易上手. 一.创建Maven ...
- 第三方开源--Android Image Cropper--图片裁剪
github下载地址:https://github.com/ArthurHub/Android-Image-Cropper 有两种使用方式: 第一种:Activity用法 1.添加 CropImage ...
- 条款36:绝对不要重新定义,继承而来的non-virtual函数
重新定义一个继承而来的non-virtual函数可能会使得导致当函数被调用的时候,被调用的函数不是取决于调用的函数究竟属于的对象,而是取决于调用函数的指针或者引用的类型. 所以一般的说主要有两种观点在 ...
- EmbarrassedBird网站
试想现在有如下情景 (情景1) 你写了一封情书准备给心中暗恋很久很久的小Z同学, 我们假设, 你提起来超级无敌巨大的勇气把情书直接交给了小Z, 现在有两种情况 a. 小Z也喜欢你, 欢乐大结局! b. ...
- cmd命令之查看进程到杀掉进程
1. cmd命令查看当前进程 netstat -ano | findstr “port”
- 学习汤姆大叔《深入理解JavaScript系列》有感(1) —— 立即调用的函数表达式
一. 下面代码用于理解函数的声明和调用. function makeCounter() { // 只能在makeCounter内部访问i var i = 0; return function () { ...
- uva11609(组合数学,快速幂)
先选人,再从这些人里选一个队长,方案总数:C(i,1)*C(n,i)(其中i从1到n)的总和. 这个公式显然不能在时限内暴力算出来,需要变形和推导出更简单的来. 用到组合数里面这个公式:C(n,k)* ...
- Storm的并行度、Grouping策略以及消息可靠处理机制简介
转自:https://my.oschina.net/zc741520/blog/409949 概念: Workers (JVMs): 在一个节点上可以运行一个或多个独立的JVM 进程.一个Topolo ...
- rabbitmq的vhost与用户管理
当我们在创建用户时,会指定用户能访问一个虚拟机,并且该用户只能访问该虚拟机下的队列和交换机,如果没有指定,默认的是”/”;一个rabbitmq服务器上可以运行多个vhost,以便于适用不同的业务需要, ...
- hdu 1028 && hdu 1398 && hdu 1085 && hdu 1171 ——生成函数
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1028 就是可以用任意个1.2.3....,所以式子写出来就是这样:(1+x+x^2+...)(1+x^2+ ...