题意

有nnn个关卡,第iii关可以花费aia_iai​的代价打一颗星,bib_ibi​的代价打两颗星。保证1≤ai<bi≤1091\le a_i<b_i\le10^91≤ai​<bi​≤109,问要达到www颗星最少花费。

题解

就是 hdu6698.Coinshdu 6698.Coinshdu6698.Coins 的弱化版。

hduhduhdu多校赛上是要查询要达到1→2n1\to 2n1→2n的所有每个www的答案。

先把bi减去ai得到新的bi,要获取第二颗星的代价就是新的bi。

然后下面的硬币表示星,硬币组就是关卡。

  • 先将硬币组分成两类,第一类 ai < bi,第二类 ai ≥ bi,并记 g(x) 为从第一类硬币组中符合限制地取出 x 枚硬币的最大价值和,令 h(x) 为从第二类硬币组中符合限制地取出 x 枚硬币的最大价值和。
  • 要求出 g,只需要将第一类的所有硬币按价值从小到大排序,则 g(x) 为前 x 个硬币的和。因为 ai < bi,可以发现在这个贪心方法中,如果选了 bi,则一定会先选了 ai;
  • 要求出 h,需要观察到:第二类硬币中最多只有一组硬币,会选了 ai 而没有选 bi。因为如果有两组硬币i, j, 满足 ai ≥ bi, aj ≥ bj,且某个方案只选了 ai, aj 而没有选 bi, bj,不失一般性,令 aj ≥ ai,那么有 aj ≥ ai ≥ bi,所以选 (ai, bi) 而不选 (aj , bj) 是个更优解,这时需要按 a + b 的值从小到大将第二类的每组硬币排序,则 h(2x) 就是前 x 组硬币的和,h(2x + 1) 就是“前 x 组加上不在前 x 组里的最小的 a”以及“前 x + 1 组中减去前 x + 1 组中最大的 b”两种方案中的较小值。
  • 求出 g, h 之后, 立即有 f(x)=min⁡x1+x2=xg(x1)+h(x2)f(x) = \min_{x1+x2=x} g(x1)+h(x2)f(x)=minx1+x2=x​g(x1)+h(x2),朴素地计算这个 min 卷积只能做到 O(n^2),但是观察到 g 是个单调递增的凸函数而 h 是个单调递增函数,设 f(i)=min⁡jh(j)+g(i−j)f(i) = \min_{j}h(j)+g(i-j)f(i)=minj​h(j)+g(i−j),可以证明 p(x) 有单调性,利用决策单调性即可优化到 O(n log n)。

最后一段可以不看,因为CF这道题只需要求f(w),所以直接枚举x1就行了。

输出方案就存一下编号。

CODE

#include <bits/stdc++.h>
using namespace std;
inline void read(int &x) {
char ch; while(!isdigit(ch=getchar()));
for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0');
}
typedef long long LL;
const int MAXN = 600005;
int n, w, cnt1, cnt2, mn[MAXN];
struct node {
int x, y, id;
inline bool operator <(const node &o)const {
return x+y < o.x+o.y;
}
}a[MAXN], b[MAXN];
LL g[MAXN], h[MAXN];
int c[MAXN];
int main () {
read(n), read(w);
for(int i = 1, x, y; i <= n; ++i) {
read(x), read(y); y -= x;
if(x < y) a[++cnt1] = (node){ x, 0, i }, a[++cnt1] = (node){ y, 0, i };
else b[++cnt2] = (node){ x, y, i };
}
sort(a + 1, a + cnt1 + 1);
sort(b + 1, b + cnt2 + 1);
memset(g, -1, sizeof g); g[0] = 0;
memset(h, -1, sizeof h); h[0] = 0;
for(int i = 1; i <= cnt1; ++i) g[i] = g[i-1] + a[i].x;
mn[cnt2+1] = 1000000000;
for(int i = cnt2; i >= 1; --i) mn[i] = min(mn[i+1], b[i].x);
for(int i = 1, j, mx = 0; i <= cnt2<<1; ++i)
if(i&1) j = (i+1)>>1, h[i] = min(h[i-1] + mn[j], h[i-1] + b[j].x + b[j].y - mx), mx = max(mx, b[j].y);
else j = i>>1, h[i] = h[i-2] + b[j].x + b[j].y;
LL ans = 1ll<<60; int i=0;
for(int j = 0; j <= w; ++j)
if(~g[w-j] && ~h[j] && g[w-j]+h[j] < ans) ans = g[w-j]+h[j], i = j;
printf("%lld\n", ans);
for(int j = 1; j <= w-i; ++j) ++c[a[j].id];
int x = (i&1) ? (i+1)>>1 : i>>1;
for(int j = 1; j <= x; ++j) c[b[j].id] += 2;
if(i&1) {
if(h[i] == h[i-1] + mn[x]) {
c[b[x].id] -= 2;
for(int j = x; j <= cnt2; ++j)
if(b[j].x == mn[x]) { ++c[b[j].id]; break; }
}
else {
int mx = h[i-1] + b[x].x + b[x].y - h[i];
for(int j = 1; j < x; ++j) if(b[j].y == mx) { --c[b[j].id]; break; }
}
}
for(int j = 1; j <= n; ++j) printf("%d", c[j]);
}

CF436E Cardboard Box(贪心)的更多相关文章

  1. 题解-CF436E Cardboard Box

    题面 CF436E Cardboard Box \(n\) 个关卡,对每个关卡可以花 \(a_i\) 时间得到 \(1\) 颗星,或花 \(b_i\) 时间得到 \(2\) 颗星,或不玩.问获得 \( ...

  2. Codeforces 436E Cardboard Box (看题解)

    Cardboard Box 贪了个半天贪不对, 我发现我根本就不会贪心. 我们先按b排序, 然后枚举选两颗心的b的最大值, 在这个之前的肯定都要选一个, 因为前面的要是一个都没选的话, 你可以把当前选 ...

  3. Codeforces 436E - Cardboard Box(贪心/反悔贪心/数据结构)

    题面传送门 题意: 有 \(n\) 个关卡,第 \(i\) 个关卡玩到 \(1\) 颗星需要花 \(a_i\) 的时间,玩到 \(2\) 颗星需要 \(b_i\) 的时间.(\(a_i<b_i\ ...

  4. Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) B. Box 贪心

    B. Box Permutation p is a sequence of integers p=[p1,p2,-,pn], consisting of n distinct (unique) pos ...

  5. upc组队赛12 Cardboard Container【枚举】

    Cardboard Container Problem Description fidget spinners are so 2017; this years' rage are fidget cub ...

  6. CF数据结构练习

    1. CF 438D The Child and Sequence 大意: n元素序列, m个操作: 1,询问区间和. 2,区间对m取模. 3,单点修改 维护最大值, 取模时暴力对所有>m的数取 ...

  7. SGU 495. Kids and Prizes

    水概率....SGU里难得的水题.... 495. Kids and Prizes Time limit per test: 0.5 second(s)Memory limit: 262144 kil ...

  8. Kids and Prizes(SGU 495)

    495. Kids and Prizes Time limit per test: 0.25 second(s)Memory limit: 262144 kilobytes input: standa ...

  9. sgu 495. Kids and Prizes (简单概率dp 正推求期望)

    题目链接 495. Kids and Prizes Time limit per test: 0.25 second(s)Memory limit: 262144 kilobytes input: s ...

随机推荐

  1. Eclipse设置每行的最大字符数

    Eclipse默认宽度是 120 个字符.如下图所示(提示:格式化快捷键Ctrl + Shift + F): 设置步骤如下: 菜单栏倒数第二项,选择Window 下拉栏最后一项,选择Preferenc ...

  2. WUSTOJ 1319: 球(Java)并查集

    题目链接:1319: 球 参考:wustoj 1319 球-wust_tanyao,并查集 并查集系列:WUSTOJ 1346: DARK SOULS(Java)并查集 Description Icy ...

  3. Python+VSCode+Git【转】

    Python+VSCode+Git 学习总结 - 秦无邪 - 博客园

  4. oracle笔记之计算年龄、工龄和TRUNC

    方法一:利用months_between 函数计算 SELECT TRUNC(months_between(sysdate, birthday)/12) AS agefrom dual; 方法二:日期 ...

  5. ArcGIS SOE开发异常之 ClassFactory cannot supply requested class

    最近SOE开发一个功能,辛辛苦苦写完, 异常: ClassFactory cannot supply requested class 辛苦解决: 百度一下,描述这个问题的帖子很多,不过内容基本一致.大 ...

  6. A Story of One Country (Hard) CodeForces - 1181E2 (分治)

    大意: 给定$n$个平面上互不相交的矩形. 若一个矩形区域只包含一个矩形或者它可以水平或垂直切成两块好的区域, 那么这个矩形区域是好的. 求判断整个平面区域是否是好的. 分治判断, 可以用链表实现删除 ...

  7. redis哈希表数据类型键的查询和删除命令

    一.查询 命令名称:hget 语法:hget key field 功能:返回哈希表key中给定域field的值 返回值: 给定域的值. 当给定域不存在或是给定key不存在时,返回nil 命令名称:hg ...

  8. 面试必问:Golang高阶-Golang协程实现原理

    引言 实现并发编程有进程,线程,IO多路复用的方式.(并发和并行我们这里不区分,如果CPU是多核的,可能在多个核同时进行,我们叫并行,如果是单核,需要排队切换,我们叫并发) 进程和线程的区别 进程是计 ...

  9. 谷歌浏览器调用activex控件方法

    原文转自 https://jingyan.baidu.com/article/af9f5a2d0ebe5543140a4596.html activex是由微软开发,所以在支持上,目前原生态支持的只有 ...

  10. MM-发票校验与收货的差异处理

    SAP FI-财务发票校验修改金额后没有进入差异科目问题:公司新建物料采购订单,在MM科目自动确定配置完成后,做发票校验时,修改金额没修改数量时,差异进入了原材料科目 换采购订单继续测试时,修改金额没 ...