A: 石子合并

所求问题:1到n这些石子合并最少需要多少代价

由于石子合并的顺序可以任意,我们将石子分为两个部分

子问题:1到k这堆石子合并,k+1到n这堆石子合并,再把两堆石子合并,需要多少代价\((1<=k<=n)\)

那么便可以得到状态转移方程 $$dp[i][j]=min(dp[i][k]+dp[k+1][j]+……)$$

i到j这些石子合并,代价不仅仅是分开的两堆内部合并的代价,还有两堆石子相互合并的所带来的代价消耗,可得出省略号中的答案为a[i]+a[i+1]+……+a[j]

为了加快效率,我们设立一个sum数组来记录前缀和,那么可得到完整的状态转移方程:

\(dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])\)

需要注意的是,由于dp求最小值,需要将dp预处理为无穷大

#include<bits/stdc++.h>
using namespace std;
const int N = 310;
int a[N], n;
int dp[N][N], sum[N];
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; ++i)cin >> a[i], dp[i][i] = 0, sum[i] = sum[i - 1] + a[i];
//F[l,r] = min(F[l,k],F[k + 1.r] + sum[l,r]
for (int len = 1; len < n; len++)
for (int i = 1; i <= n - len; i++){
int j = i + len;
for (int k = i; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]);
}
cout << dp[1][n] << endl;
}

B: Polygon

题目描述

Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an integer and each edge is labelled with either the symbol + (addition) or the symbol * (product). The edges are numbered from 1 to N.



On the first move, one of the edges is removed. Subsequent moves involve the following steps:

  1. pick an edge E and the two vertices V1 and V2 that are linked by E; and
  2. replace them by a new vertex, labelled with the result of performing the operation indicated in E on the labels of V1 and V2.

The game ends when there are no more edges, and its score is the label of the single vertex remaining.

Consider the polygon of Figure 1. The player started by removing edge 3. After that, the player picked edge 1, then edge 4, and, finally, edge 2. The score is 0.



Write a program that, given a polygon, computes the highest possible score and lists all the edges that, if removed on the first move, can lead to a game with that score.

输入描述:

Your program is to read from standard input. The input describes a polygon with N vertices. It contains two lines. On the first line is the number N. The second line contains the labels of edges 1, ..., N, interleaved with the vertices' labels (first that of the vertex between edges 1 and 2, then that of the vertex between edges 2 and 3, and so on, until that of the vertex between edges N and 1), all separated by one space. An edge label is either the letter t (representing +) or the letter x (representing *).

$3 <= N <= 50 $

For any sequence of moves, vertex labels are in the range \([-32768,32767]\).

输出描述:

Your program is to write to standard output. On the first line your program must write the highest score one can get for the input polygon. On the second line it must write the list of all edges that, if removed on the first move, can lead to a game with that score. Edges must be written in increasing order, separated by one space.

输入

4
t -7 t 4 x 2 x 5

输出

33
1 2

解题思路

这道题的题意大致是对于n个点的环先删除一个点后,根据连线的运算符逐渐合并各个点,最后求最大的结果可能是多少。一道经典的区间DP题,有几个点需要注意一下:

  1. 需要枚举最开始删除的是哪条边
  2. 由于一开始是个环,删边后可能从中间断开,导致区间不连续,无法使用区间DP。解决方法是将原始数组复制一倍,这样就能保证能够使用区间DP。
  3. 由于元素可能存在负值,负负相乘得正后可能得到的结果更大。所以在维护结果的时候,既要维护最大值,也要维护最小值。
#include<bits/stdc++.h>
using namespace std;
const int N = 106, INF = 0x3f3f3f3f;
char c[N];
int a[N], dp_max[N][N], dp_min[N][N];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> c[i];
cin >> a[i];
}
for (int i = n + 1; i <= (n << 1); i++) {
c[i] = c[i - n];
a[i] = a[i - n];
}
memset(dp_max, 0xcf, sizeof(dp_max));
memset(dp_min, 0x3f, sizeof(dp_min));
for (int i = 1; i <= (n << 1); i++) dp_max[i][i] = dp_min[i][i] = a[i];
for (int len = 2; len <= n; len++)
for (int l = 1; l + len - 1 <= (n << 1); l++) {
int r = l + len - 1;
for (int k = l + 1; k <= r; k++)
if (c[k] == 't') {
dp_max[l][r] = max(dp_max[l][r], dp_max[l][k - 1] + dp_max[k][r]);
dp_min[l][r] = min(dp_min[l][r], dp_min[l][k - 1] + dp_min[k][r]);
}
else {
dp_max[l][r] = max(dp_max[l][r], max(dp_max[l][k - 1] * dp_max[k][r], dp_min[l][k - 1] * dp_min[k][r]));
dp_min[l][r] = min(dp_min[l][r], min(dp_max[l][k - 1] * dp_max[k][r], min(dp_min[l][k - 1] * dp_min[k][r], min(dp_max[l][k - 1] * dp_min[k][r], dp_min[l][k - 1] * dp_max[k][r]))));
}
}
int ans = -INF;
for (int i = 1; i <= n; i++) ans = max(ans, dp_max[i][i + n - 1]);
cout << ans << endl;
for (int i = 1; i <= n; i++)
if (ans == dp_max[i][i + n - 1])
cout << i << " ";
return 0;
}

C:金字塔

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9;
ll f[310][310];
string s;
ll dfs(int l, int r) {
if (l > r) return 0;//递归边界
if (l == r) return 1;//递归边界
if (f[l][r] != -1) return f[l][r];//记忆化
if (s[l] != s[r]) return 0;
f[l][r] = 0;
for (int k = l + 2; k <= r; k++)
(f[l][r] += dfs(l + 1, k - 1) * dfs(k, r)) %= mod;
return f[l][r];
} int main() {
//freopen("in.txt", "r", stdin);
memset(f, -1, sizeof f);//-1代表没有计算过
cin >> s;
cout << dfs(0, s.length() - 1) << endl;
}

0x53 动态规划-区间DP的更多相关文章

  1. 动态规划——区间dp

    在利用动态规划解决的一些实际问题当中,一类是基于区间上进行的,总的来说,这种区间dp是属于线性dp的一种.但是我们为了更好的分类,这里仍将其单独拿出进行分析讨论. 让我们结合一个题目开始对区间dp的探 ...

  2. 动态规划——区间DP,计数类DP,数位统计DP

    本博客部分内容参考:<算法竞赛进阶指南> 一.区间DP 划重点: 以前所学过的线性DP一般从初始状态开始,沿着阶段的扩张向某个方向递推,直至计算出目标状态. 区间DP也属于线性DP的一种, ...

  3. 模板 - 动态规划 - 区间dp

    因为昨天在Codeforces上设计的区间dp错了(错过了上紫的机会),觉得很难受.看看学长好像也有学,就不用看别的神犇的了. 区间dp处理环的时候可以把序列延长一倍. 下面是 $O(n^3)$ 的朴 ...

  4. 动态规划---区间dp

    今天写内网题,连着写了两道区间dp,这里就总结一下. 区间dp思想主要是先枚举f[i][j]中的i,再枚举j,再枚举一个1~j之间的变量k,一般是f[i][j] = max(f[i][j],f[i][ ...

  5. [hdu contest 2019-07-29] Azshara's deep sea 计算几何 动态规划 区间dp 凸包 graham扫描法

    今天hdu的比赛的第一题,凸包+区间dp. 给出n个点m个圆,n<400,m<100,要求找出凸包然后给凸包上的点连线,连线的两个点不能(在凸包上)相邻,连线不能与圆相交或相切,连线不能相 ...

  6. Hdu OJ 5115 Dire Wolf (2014ACM/ICPC亚洲区北京站) (动态规划-区间dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5115 题目大意:前面有n头狼并列排成一排, 每一头狼都有两个属性--基础攻击力和buff加成, 每一头 ...

  7. Light OJ 1025 - The Specials Menu(动态规划-区间dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1025 题目大意:一串字符, 通过删除其中一些字符, 能够使这串字符变成回文串. ...

  8. [SCOI2007]压缩(动态规划,区间dp,字符串哈希)

    [SCOI2007]压缩 状态:设\(dp[i][j]\)表示前i个字符,最后一个\(M\)放置在\(j\)位置之后的最短字串长度. 转移有三类,用刷表法来实现. 第一种是直接往压缩串后面填字符,这样 ...

  9. [jdoj1090]矩阵_区间dp

    矩阵 jdoj-1910 题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数. 注释:1<=n< ...

  10. 动态规划(区间DP):HDU 5115 Dire Wolf

    Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not ...

随机推荐

  1. 神经网络入门篇:详解随机初始化(Random+Initialization)

    当训练神经网络时,权重随机初始化是很重要的.对于逻辑回归,把权重初始化为0当然也是可以的.但是对于一个神经网络,如果把权重或者参数都初始化为0,那么梯度下降将不会起作用. 来看看这是为什么. 有两个输 ...

  2. Apache Paimon流式湖仓学习交流群成立

    Apache Paimon是一个流式数据湖平台.致力于构建一个实时.高效的流式数据湖平台.这个项目采用了先进的流式计算技术,使企业能够实时处理和分析大量数据.Apache Paimon 的核心优势在于 ...

  3. Navicat远程连接Centos8.4服务器MySQL8.0数据库

    一.首先登陆服务器后台管理,使服务器开放3306策略 二.开启远程连接 1.登陆服务器的MySQL数据库 mysql -uroot -p 2.登录成功后,切换数据库 use mysql; 3.查看当前 ...

  4. 无序对的GCD

    求\(\sum_{i = 1}^n \sum_{j = i+1}^n GCD(a_i, a_j)\) \(N\)为上确界,\(n\)为\(a\)数组元素个数,\(D\)为约数个数. 方法一 \(1.\ ...

  5. 解决win10的wifi打不开或无法搜索到周围wifi的问题

    今天笔者遇到了一个比较奇葩的问题,就是笔记本电脑的wifi打不开了,即使打开了也是搜索不到周围的wifi的.这个问题一开始笔者没有发现,因为在暑假期间都是使用笔记本连接自己的手机热点进行上网的.然而暑 ...

  6. Java8函数式编程应用

    我们经常提到,Java8是革命性的一个版本,原因就是正式引入了函数式编程,那Java的函数式编程在实际应用中到底有什么用呢?结合实际的应用,我整理出了函数式在Java的几个经典用途. 缓求值 惰性求值 ...

  7. 关于Secure Hash Algorithm加密算法

    一.概述 SHA(Secure Hash Algorithm)加密算法是一种广泛应用的密码散列函数,由美国国家安全局(NSA)设计,用于保障数据的安全性和完整性.SHA算法经历了多个版本的更新,目前主 ...

  8. MinIO客户端之du

    MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc du 用于输出桶内对象的数量和占用的空间. 命令如下: ./mc du local1/bkt1 控制台的输出 ...

  9. 基于WebRTC的局域网文件传输

    基于WebRTC的局域网文件传输 WebRTC(Web Real-Time Communications)是一项实时通讯技术,允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点P2P ...

  10. tty详解

    linux下tty命令详解 [功能] 打印连接到标准输入的终端的文件名. [描述] 命令项: -s, --silent, --quiet: 什么也不打印,只是返回退出状态码. --help: 打印帮助 ...