题意:给你一个长度为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));
}

  

最新文章

  1. Delphi_04_Delphi_Object_Pascal_基本语法_02
  2. Maven命令
  3. p2p音视频通信
  4. as画柱型图的简单算法(关于柱型图宽和间距问题)
  5. Python小练习一
  6. javascript 设计模式-----单例模式
  7. 揣摩实现一个ioc容器需要做的事情
  8. codevs1183泥泞的道路
  9. [LeetCode]题解(python):053-Maximum Subarray
  10. hdu 2295 DLX
  11. KindEditor文件上传成功前端显示上传失败
  12. springCloud项目练习
  13. PAT乙级 1034
  14. Java面试题之基础篇概览
  15. 在servlet中使用spring注解
  16. CG-ctf WP
  17. failed to create pid file /var/run/rsyncd.pid: File exists报错
  18. 【PMP】合同类型
  19. A* 寻路学习
  20. input 文本框,对中文长度校验

热门文章

  1. python中的单引号双引号和三引号
  2. Java源码阅读的真实体会(一种学习思路)【转】
  3. 完全分布式安装hadoop集群
  4. db2还原离线备份文件报错SQL2071N 提示“访问共享库出现错误”解决
  5. 关于js序列化时间的方法
  6. 2017 年比较 Angular、React、Vue 三剑客(转载)
  7. HDU4416Good Article Good sentence(后缀自动机)
  8. MQTT协议通俗讲解
  9. 伪差IO分标准
  10. 蓝桥杯 算法训练 ALGO-118 连续正整数的和