[NOI1995] 石子合并
[NOI1995] 石子合并
题目描述
在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。
输入格式
数据的第 1 1 1 行是正整数 N N N,表示有 N N N 堆石子。
第 2 2 2 行有 N N N 个整数,第 i i i 个整数 a i a_i ai 表示第 i i i 堆石子的个数。
输出格式
输出共 2 2 2 行,第 1 1 1 行为最小得分,第 2 2 2 行为最大得分。
样例 #1
样例输入 #1
4
4 5 9 4
样例输出 #1
43
54
提示
1 ≤ N ≤ 100 1\leq N\leq 100 1≤N≤100, 0 ≤ a i ≤ 20 0\leq a_i\leq 20 0≤ai≤20。
题目大意
在一个圆形操场的四周摆放了 N N N 堆石子。每次操作中,你只能选择相邻的两堆石子进行合并,并且合并的得分是这两堆石子的数量之和。最终的目标是将所有石子合并为一堆,要求你计算出合并过程中得到的最小得分和最大得分。
解题思路
这道题目涉及到动态规划(Dynamic Programming, DP)和圆形排列的处理。我们可以将圆形的石子排列“展平”成一条线,并使用动态规划解决合并过程中的最小得分和最大得分问题。具体步骤如下:
-
展平圆形结构:由于石子的排列是圆形的,我们可以通过将数组复制一遍并拼接起来,变成一个长度为 2 N 2N 2N 的数组。这样,我们就可以将圆形结构当作一个线性结构来处理。
-
动态规划状态定义:
dp1[l][r]:表示在区间 [ l , r ] [l, r] [l,r] 内合并所有石子的最小得分。dp2[l][r]:表示在区间 [ l , r ] [l, r] [l,r] 内合并所有石子的最大得分。
-
状态转移方程:
- 计算最小得分时,我们可以选择区间内的任意一个位置进行合并,更新
dp1[l][r]:
[
dp1[l][r] = \min(dp1[l][r], dp1[l][k] + dp1[k+1][r] + sum[r] - sum[l-1])
] - 同样地,计算最大得分时更新
dp2[l][r]:
[
dp2[l][r] = \max(dp2[l][r], dp2[l][k] + dp2[k+1][r] + sum[r] - sum[l-1])
]
- 计算最小得分时,我们可以选择区间内的任意一个位置进行合并,更新
-
前缀和的计算:为了更快速地计算区间和,我们可以使用一个
sum数组,其中sum[i]表示从第一个石子到第 i i i 个石子的总和。 -
最终结果:由于是一个环形结构,我们需要对
dp1和dp2中所有可能的区间(长度为 N N N 的子区间)计算最小值和最大值。
代码分析
#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
using namespace std;const int inf = 1e9 + 7;
const int N = 300 + 10;int n;
int dp1[N][N]; // 最小得分 DP
int dp2[N][N]; // 最大得分 DP
int sum[N]; // 前缀和数组
vector<int> v(N); // 石子的数量void clear() {for (int i = 0; i < N; ++i) {for (int j = i; j < N; ++j) {if (i == j) {dp1[i][j] = 0;dp2[i][j] = 0;} else {dp1[i][j] = inf;dp2[i][j] = -inf;}}}
}void solved() {clear();cin >> n; // 读入石子的堆数for (int i = 1; i <= n; ++i) {cin >> v[i];sum[i] = sum[i - 1] + v[i]; // 计算前缀和}// 扩展石子数组,处理圆形结构for (int i = n + 1; i <= 2 * n; ++i) {v[i] = v[i - n];sum[i] = sum[i - 1] + v[i];}// 计算 dp 数组for (int len = 2; len <= n; ++len) { // 长度从2到nfor (int l = 1; l <= 2 * n - len + 1; ++l) { // 枚举区间起始位置int r = l + len - 1; // 区间的右端for (int k = l; k < r; ++k) { // 枚举分割点dp1[l][r] = min(dp1[l][r], dp1[l][k] + dp1[k + 1][r] + sum[r] - sum[l - 1]);dp2[l][r] = max(dp2[l][r], dp2[l][k] + dp2[k + 1][r] + sum[r] - sum[l - 1]);}}}int minn = inf, maxx = -inf;for (int l = 1; l <= n; ++l) { // 最终结果遍历所有可能的起始位置minn = min(minn, dp1[l][l + n - 1]);maxx = max(maxx, dp2[l][l + n - 1]);}cout << minn << endl; // 输出最小得分cout << maxx << endl; // 输出最大得分
}signed main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int T = 1;while (T--) {solved();}
}
代码分析
-
初始化和前缀和:首先初始化
dp1和dp2数组,dp1[i][j]用于保存区间 [ i , j ] [i, j] [i,j] 的最小合并得分,dp2[i][j]用于保存区间 [ i , j ] [i, j] [i,j] 的最大合并得分。我们也通过sum数组计算了从第一个石子到第 i i i 个石子的前缀和。 -
展开圆形数组:由于问题中石子是圆形排列的,我们通过将数组从头到尾复制一次,形成一个长度为 2 N 2N 2N 的新数组
v,并且更新对应的前缀和sum。 -
动态规划计算:通过枚举区间长度
len和起始位置l,以及每个区间内的分割点k,使用状态转移方程更新dp1和dp2数组。最终,通过遍历所有可能的区间,找到最小得分和最大得分。 -
时间复杂度:由于有三重循环(区间长度、区间起点、分割点),时间复杂度为 O ( N 3 ) O(N^3) O(N3)。对于 N ≤ 100 N \leq 100 N≤100,这种复杂度是可以接受的。
总结
这个问题的核心在于如何利用动态规划求解合并石子的最小和最大得分。通过将圆形结构展开为线性结构,可以简化问题的求解。算法通过动态规划计算每个区间的最小和最大得分,并最终遍历所有可能的区间来求解答案。
相关文章:
[NOI1995] 石子合并
[NOI1995] 石子合并 题目描述 在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出一个算法,计算出将 …...
真正的智能与那只蝴蝶
“蝴蝶效应”可以展开为对智能本质与大算力关系的追问,其中“蝴蝶”作为隐喻可能指向多重维度——从混沌理论的“蝴蝶效应”到庄子“物我两忘”的蝴蝶之梦。这种并置本身暗示了智能与宇宙秩序、认知边界之间的深刻张力。以下从三个层面展开分析:一、混沌…...
C++小病毒-1.0勒索(更新次数:2)
内容供学习使用,不得转卖,代码复制后请1小时内删除,此代码会危害计算机安全,谨慎操作 在C20环境下,并在虚拟机里运行此代码!,病毒带来后果自负! 使用时请删除在main()里的注释,并修改位置至C:\\(看我代码注释)//可以改成WIN Main() #include <iostream> #i…...
Node.js 的底层原理
Node.js 的底层原理 1. 事件驱动和非阻塞 I/O Node.js 基于 Chrome V8 引擎,使用 JavaScript 作为开发语言。它采用事件驱动和非阻塞 I/O 模型,使其轻量且高效。通过 libuv 库实现跨平台的异步 I/O,包括文件操作、网络请求等。 2. 单线程事…...
基于Django的豆瓣影视剧推荐系统的设计与实现
【Django】基于Django的豆瓣影视剧推荐系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统采用了Python作为后端开发语言,采用Django作为后端架构,结…...
P10638 BZOJ4355 Play with sequence Solution
Description 给定 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1,a2,⋯,an),有 m m m 个操作,分以下三种: assign ( l , r , k ) \operatorname{assign}(l,r,k) assign(l,r,k):对每个 i ∈ [ l , r ] i \…...
MySQL误删数据怎么办?
文章目录 1. 从备份恢复数据2. 通过二进制日志恢复数据3. 使用数据恢复工具4. 利用事务回滚恢复数据5. 预防误删数据的策略总结 在使用MySQL进行数据管理时,误删数据是一个常见且具有高风险的操作。无论是因为操作失误、系统故障,还是不小心执行了删除命…...
项目测试之MockMvc
文章目录 基础基础概念Mockxxx一般实现文件位置 实战MockMvc与Test注解不兼容RequestParams参数RequestBody参数 基础 基础概念 定义:是Spring框架提供的一种用于测试Spring MVC控制器的工具,它允许开发者在不启动完整的web服务器的情况下,…...
Unbutu虚拟机+eclipse+CDT编译调试环境搭建
问题1: 安装CDT,直接Help->eclipse Market space-> 搜cdt , install,等待重启即可. 问题2:C变量不识别vector ’could not be resolved 这是库的头文件没加好,右键Properties->C Build->Enviroment,增加…...
时间轮:XXL-JOB 高效、精准定时任务调度实现思路分析
大家好,我是此林。 定时任务是我们项目中经常会遇到的一个场景。那么如果让我们手动来实现一个定时任务框架,我们会怎么做呢? 1. 基础实现:简单的线程池时间轮询 最直接的方式是创建一个定时任务线程池,用户每提交一…...
CTF-web: Python YAML反序列化利用
PyYAML存在以下几个特殊标签,如果这些标签被不安全的解析,会造成解析漏洞 从 PyYaml 版本 6.0 开始,load 的默认加载器已切换到 SafeLoader,以降低远程代码执行的风险。更新后易受攻击的是 yaml.unsafe_load 和 yaml.load(input, Loaderyaml.UnsafeLoade…...
代码随想录算法训练营第三十八天-动态规划-完全背包-139.单词拆分
类似于回溯算法中的拆分回文串题目是要求拆分字符串,问这些字符串是否出现在字典里。但这道题可以反着来考虑,从字典中的单词能不能组成所给定的字符串 如果这样考虑, 这个字符串就背包,容器字典中的单词就是一个一个物品问题就转…...
ML基础-Jupyter notebook中的魔法命令
在 Jupyter Notebook 或 IPython 环境中,“魔法命令”(Magic Commands)是一些以百分号(%)或惊叹号(!)开头的特殊命令,用于执行一些与代码运行环境相关的操作,而不仅仅是执行普通的 P…...
Zookeeper入门部署(单点与集群)
本篇文章基于docker方式部署zookeeper集群,请先安装docker 目录 1. docker初期准备 2.启动zookeeper 2.1 单点部署 2.2 集群部署 3. Linux脚本实现快速切换启动关闭 1. docker初期准备 拉取zookeeper镜像 docker pull zookeeper:3.5.6 如果拉取时间过长…...
Kafa分区策略实现
引言 Kafka 的分区策略决定了生产者发送的消息会被分配到哪个分区中,合理的分区策略有助于实现负载均衡、提高消息处理效率以及满足特定的业务需求。 轮询策略(默认) 轮询策略是 Kafka 默认的分区策略(当消息没有指定键时&…...
Pyside/Pyqt中QWebEngineView和QWebEnginePage的区别
在 PySide/Qt 的 WebEngine 模块中,QWebEngineView 和 QWebEnginePage 是两个紧密相关但职责不同的类。以下是它们的核心区别和关系: 1. 职责区分 类名核心职责模块归属QWebEngineView作为可视化的窗口部件(Widget),负…...
Kafka的内部通信协议
引言 kafka内部用到的常见协议和优缺点可以看看原文 Kafka用到的协议 本文奖详细探究kafka核心通信协议和高性能的关键 网络层通信的实现 基于 Java NIO:Kafka 的网络通信层主要基于 Java NIO 来实现,这使得它能够高效地处理大量的连接和数据传输。…...
强大到工业层面的软件
电脑数据删不干净,简直是一种让人抓狂的折磨!明明已经把文件扔进了回收站,清空了,可那些残留的数据就像牛皮癣一样,怎么也除不掉。这种烦恼简直无处不在,让人从头到脚都感到无比烦躁。 首先,心…...
数据分析和AI丨应对AI实施挑战,工程领域AI应用的五大方法
工程领域的人工智能 (AI) 已经开始发挥价值,低代码和无代码工具正在使曾经仅属于专业数据科学家的 AI 能力变得大众化。 然而,并非工程领域的每个人都能从中受益,使用新的便捷的 AI 工具提高工作效率并不难,…...
54. UDP协议
UDP协议 UDP(User Datagram Protocol,用户数据报协议)是一个无连接的传输层协议,它提供简单的、不可靠的信息传送服务。与TCP(传输控制协议)不同,UDP不提供数据包的排序、错误检查(仅…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
