代码源 每日一题 分割 洛谷 P6033合并果子
题目链接:切割 - 题目 - Daimayuan Online Judge
数据加强版链接: [NOIP2004 提高组] 合并果子 加强版 - 洛谷
题目描述
有一个长度为 ∑ai 的木板,需要切割成 n 段,每段木板的长度分别为 a1,a2,…,an。
每次切割,会产生大小为被切割木板长度的开销。
请你求出将此木板切割成如上 nn 段的最小开销。
输入格式
第 1 行一个正整数表示 n。
第 2 行包含 nn 个正整数,即 a1,a2,…,an。
输出格式
输出一个正整数,表示最小开销。
数据范围
对于全部测试数据,满足 1≤n,ai≤10^5。
样例输入:
5
5 3 4 4 4
样例输出:
47
nlogn解法
核心思想:贪心
正向考虑题意的话,需要每次将长木板较平均的分割成两块,再每次分割出里面最小的,怎么才最平均呢?还得找最大值?个人觉得不是那么好处理,可以考虑下逆向思维,转换一下题意。
如何转换题意呢?将一块长木板分割为n段,每次的花费为被分割的木板长度,可以等价于被分割成的两块合成一块时,花费为合成的两块的长度和,便转化成了怎样使它合并成一块的花费最小问题。(举个例子,就比如一个长为4的分成一个1一个3,花费为4,跟一个1和一个3合并成一个4,花费为1+3时等价的)
思路:
考虑每次取出两个最小的合成一个更大的,直到最后只剩一个。
证明:
怎么证明这个贪心是对的呢?我们可以假设有三个木块a1<a2<a3,如果取a1,a2合并,需要的花费为(a1+a2)+(a1+a2+a3),如果不取两个最小的,而取a2,a3,需要花费为(a2+a3)+(a2+a3+a1)显然比第一种要大。那么如何推广到一般情况呢?我们可以这样想,合并了两个之后,费用肯定要加上两个的和,两个合并成的一个肯定还需要与其他的合并,而用递归去想这一部分的花费可以看成是大小固定的,就是说你合并成的还需要去和其他的合并求和,而最终下次合并的和是相同的,那么让两个合并的花费尽量小,花费不就小了吗?
代码实现
怎样每次找到两个最小的呢,并加入合并成的那个?我们考虑使用STL自带的最小堆-优先队列priority_queue。
复杂度分析:
优先队列的插入查询均为logn,复杂度为O(n)*O(logn)即O(nlogn)。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long //会爆int,所以改为了longlong
priority_queue<int, vector<int>, greater<int>> q; //小根堆
int n, ans;
signed main()
{
scanf("%lld", &n);
for (; n--;)
{
int x;
scanf("%lld", &x);
q.push(x); //初始将n个木块加入
}
while (q.size() >= 2)
{
int x1, x2;
x1 = q.top(), q.pop(); //取出两次堆顶
x2 = q.top(), q.pop();
ans += (x1 + x2);
q.push(x1 + x2); //加入合并的木块
}
cout << ans << "\n";
}
O(n)解法
考虑优化掉每次插入查询的logn。每次合并成的新的木板肯定是载增大的,也就是说合成的木板是有序的,那么我们使没有被合并的那些木板变得有序,每次考虑取两者队首元素中较小的,用两个队列维护,因为有序所以队首元素为最小值。对初始队列的排序考虑桶排。可以在On的时间内完成此题了。(洛谷貌似卡读入了,所以加了个快读)
详见代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll a[100009]; //记录大小为i的木板的数量(桶排)
ll ans;
void read(int &x) //优化读入
{
int f = 1;
x = 0;
char s = getchar();
while (s < '0' || s > '9')
{
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9')
{
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int main()
{
int n;
read(n);
for (int i = 1; i <= n; i++)
{
int x;
read(x);
a[x]++; //大小为x的数量+1
}
queue<ll> pre, added; // pre为原始的木板队列,added为后来合并加入的队列
for (int i = 1; i <= 100000; i++)
{
while (a[i]--) //因为i可能不止一个
{
pre.push(i); //放入队列中,使得pre是有序的
}
}
for (int i = 1; i <= n - 1; i++) // n个需要合并n-1次
{
ll x1, x2;
if ((!pre.empty() && !added.empty() && pre.front() < added.front()) || added.empty()) // pre的队首小于added的队首或者added为空
{
x1 = pre.front(); //从pre取
pre.pop();
}
else
{
x1 = added.front(); //从added取
added.pop();
}
//重复一次操作取x2
if ((!pre.empty() && !added.empty() && pre.front() < added.front()) || added.empty()) // pre的队首小于added的队首或者added为空
{
x2 = pre.front();
pre.pop();
}
else
{
x2 = added.front();
added.pop();
}
ans += (x1 + x2); //加上花费
added.push(x1 + x2); // added中加入新合成的木板
}
cout << ans;
}
代码源 每日一题 分割 洛谷 P6033合并果子的更多相关文章
- 堆学习笔记(未完待续)(洛谷p1090合并果子)
上次讲了堆,别人都说极其简单,我却没学过,今天又听dalao们讲图论,最短路又用堆优化,问懂了没,底下全说懂了,我???,感觉全世界都会了堆,就我不会,于是我决定补一补: ——————来自百度百科 所 ...
- 【洛谷P1090 合并果子】
题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可 ...
- 洛谷P1090 合并果子
合并果子 题目链接 这个只能用于结构体中 struct item { int val; friend bool operator < (item a,item b) { return a.val ...
- [NOIP2004] 提高组 洛谷P1090 合并果子
题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可 ...
- 洛谷 p1090 合并果子
https://www.luogu.org/problemnew/show/P1090 优先队列的经典题目 体现了stl的优越性 #include<bits/stdc++.h> using ...
- 洛谷 P1090合并果子【贪心】【优先队列】
题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可 ...
- 洛谷P1090 合并果子【贪心】
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和.可以看出,所 ...
- Java实现 洛谷 P1090 合并果子
import java.io.BufferedInputStream; import java.util.Arrays; import java.util.Scanner; public class ...
- 洛谷P1090——合并果子(贪心)
https://www.luogu.org/problem/show?pid=1090 题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合 ...
随机推荐
- MariaDB CTE公用表达式
公用表达式(Common Table Expressions,简称CTE) Maria DB 版本为10.2.2以上的才支持 WITH 语法 CTE 介绍 WITH关键字表示公用表表达式(CTE) 它 ...
- 解释 MySQL 外连接、内连接与自连接的区别 ?
先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一 个表的所有记录和另一个表中的所有记录一一匹配. 内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合 条 ...
- 解释Spring框架中bean的生命周期?
Spring容器 从XML 文件中读取bean的定义,并实例化bean. Spring根据bean的定义填充所有的属性. 如果bean实现了BeanNameAware 接口,Spring 传递bean ...
- 学习heartbeat-05 实现web服务高可用
一.环境介绍 说明:所有案例在虚拟机(VMware)上完成 操作系统:centos 6.5 64bit 高可用软件:heartbeat 3.0.4 Web应用服务器:apache httpd 2.2. ...
- Vue报错之"[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead......"
一.报错截图 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the p ...
- 【Visual Studio】VS 提示图标的含义
一.前言 vs 中提示图标是什么意思 二.正文 信号图标 以下信号图标应用于所有原有的图标并指示它们的辅助功能. 图标 描述 <No Signal Icon> Public. 可从此组件中 ...
- MOS管驱动电路,看这里就啥都懂了
一.MOS管驱动电路综述在使用MOS管设计开关电源或者马达驱动电路的时候,大部分人都会考虑MOS的导通电阻,最大电压等,最大电流等,也有很多人仅仅考虑这些因素.这样的电路也许是可以工作的,但并不是优秀 ...
- HTML5相关文章和资源
Polyfills HTML5 Cross Browser Polyfills canvas HTML5 JS实现毛玻璃效果(高斯模糊) 高斯模糊的算法Canvas 内部元素添加事件处理 应用场景 P ...
- html dom 转化成图片踩坑记(canvas toDataURL)
需求 在开发过程中遇到这么一个需求,h5页面需要将一个html dom转化成图片,便于用户保存. 面向百度搜索第三方得 html2canvas 和 dom-to-image 两者在写这篇笔记之前在gi ...
- 用 JS(JavaScript )实现增删改查
JS小例题 学习内容: 需求 总结: 学习内容: 需求 用 JavaScript 实现简单增删改查 实现代码 <!DOCTYPE html PUBLIC "-//W3C//DTD HT ...