题目描述

有\(n\)个物品,每个物品有一个体积\(v_i\),背包容量\(s\)。要求选一些物品恰好装满背包且物品个数最少,并在这样的方案中:

(1)求出中位数最小的方案的中位数(\(k\)个元素的中位数是从小到大第\(⌊k/2⌋\)个数);

(2)求出众数最小的方案的众数;

(3)求出极差最小的方案的极差。

解题思路

令每个物品价值为1,求装满时的最小价值,这只需01背包即可,答案即为最小个数\(m\)。

对于众数,二分答案并删去多余物品即可。

对于中位数,二分答案,令每个物品价值为\(inf+t\),其中体积大于二分的答案时\(t\)为1,否则为-1。同样求出装满时最小价值,若超过\(m\times inf\)则真正答案更大,否则更小。正确性是因为任意时刻,\(dp_i\)保存的值若要求最优,首先要保证取的个数是最少的(否则没有意义),在此条件下尽可能少取体积大的物品。而全局最优答案必然由局部最优答案转移(可反证)。

对于极差,考虑从小到大加入物品,每个物品价值\(inf\),但是若该物品第一次加入背包则价值\(inf-v_i\)。每加完一个物品\(i\)更新完\(dp\)后,求\(dp_s+v_i\)。所有值取最小即可。

时间复杂度\(O(ns \log n)\)

一些感受

根据以上思路,除了极差部分可全部转化为普通01背包,大大减小了代码量(仅60行)。极差部分也非常好写,详见代码。

可惜比赛时没想出来!赛后过了若干天补题时想了一会就出来了(生气~)。最后,这道题质量真是太高啦!“题出的好!难度适中,覆盖知识点广,题目又着切合实际的背景,解法比较自然。给出题人点赞!”

AC代码

 #include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXV 5001
#define INF 10001
int dp[MAXV];
int v[], c[];
int solve(int n, int s)
{
memset(dp, 0x3f, sizeof(dp));
dp[] = ;
for (int i = ; i < n; i++){
for (int j = s; j >= v[i]; j--)
dp[j] = min(dp[j], dp[j - v[i]] + c[i]);
}
return dp[s];
}
int solve2(int n, int s)
{
memset(dp, 0x3f, sizeof(dp));
dp[] = ;
int ans = 0x3fffffff;
for (int i = ; i < n; i++){
for (int j = s; j > v[i]; j--)
dp[j] = min(dp[j], dp[j - v[i]] + INF);
dp[v[i]] = min(dp[v[i]], INF - v[i]);
ans = min(ans, dp[s] + v[i]);
}
return ans % INF;
}
int main()
{
int n, s;
scanf("%d%d", &n, &s);
for (int i = ; i < n; i++){
scanf("%d", &v[i]);
c[i] = ;
}
sort(v, v + n);
int num = solve(n, s), l, r;
if (num > n){ printf("-1"); return ; }
printf("%.9lf ", (double)s / num);
for (l = , r = n - ; l != r;){
int mid = (l + r) >> , w = v[mid];
for (int i = ; i < n; i++)
c[i] = INF + (v[i] > w ? : -);
if (solve(n, s) > INF * num)l = mid + ;
else r = mid;
}
printf("%d ", v[l]);
for (l = , r = n; l != r;){
int mid = (l + r) >> ;
for (int i = , j; i < n; i++){
j = !i || v[i] != v[i - ] ? : j + ;
c[i] = j <= mid ? : INF;
}
if (solve(n, s) > num)l = mid + ;
else r = mid;
}
printf("%d ", l);
printf("%d", solve2(n, s));
return ;
}

一道背包神题-Petrozavodsk Winter-2018. Carnegie Mellon U Contest Problem I的更多相关文章

  1. hdu 6021 MG loves string (一道容斥原理神题)(转)

    MG loves string    Accepts: 30    Submissions: 67  Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  2. 【CZY选讲·一道图论神题】

    题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图,只有点权. LYK想把这个图删干净,它的方法是这样的.每次选择一个点,将它删掉,但删这个点是需要代价的 ...

  3. 清北学堂模拟赛d2t1 一道图论神题(god)

    题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图,只有点权. LYK想把这个图删干净,它的方法是这样的.每次选择一个点,将它删掉,但删这个点是需要代价的.假 ...

  4. day2 上午 游戏 对应关系--->判断素数---->多重背包 神题

    #include<iostream> using namespace std; int n; ; ]; long long p[maxn]; long long dp[maxn][maxn ...

  5. Petrozavodsk Winter-2018. Carnegie Mellon U Contest

    A. Mines 每个点能爆炸到的是个区间,线段树优化建图,并求出SCC进行缩点. 剔除所有不含任何$n$个点的SCC之后,最小代价为每个入度为$0$的SCC中最小点权之和,用set维护即可. 时间复 ...

  6. Codeforces 1090A - Company Merging - [签到水题][2018-2019 Russia Open High School Programming Contest Problem A]

    题目链接:https://codeforces.com/contest/1090/problem/A A conglomerate consists of n companies. To make m ...

  7. Codeforces 1090D - Similar Arrays - [思维题][构造题][2018-2019 Russia Open High School Programming Contest Problem D]

    题目链接:https://codeforces.com/contest/1090/problem/D Vasya had an array of n integers, each element of ...

  8. Codeforces 1090M - The Pleasant Walk - [签到水题][2018-2019 Russia Open High School Programming Contest Problem M]

    题目链接:https://codeforces.com/contest/1090/problem/M There are n houses along the road where Anya live ...

  9. 洛谷P2918 [USACO08NOV]买干草(一道完全背包模板题)

    题目链接 很明显的一道完全背包板子题,做法也很简单,就是要注意 这里你可以买比所需多的干草,只要达到数量就行了 状态转移方程:dp[j]=min(dp[j],dp[j-m[i]]+c[i]) 代码如下 ...

随机推荐

  1. 分析ELF的加载过程

    http://blog.chinaunix.net/uid-72446-id-2060538.html 对于可执行文件来说,段的加载位置是固定的,程序段表中如实反映了段的加载地址.对于共享库来?段的加 ...

  2. 3218: 字符串字符统计—C语言

    3218: 字符串字符统计—C语言 时间限制: 1 Sec  内存限制: 128 MB提交: 270  解决: 129[提交][状态][讨论版][命题人:smallgyy] 题目描述 编写一函数,由实 ...

  3. 在O(1)时间复杂度删除链表节点

    题目描述: 给定一个单链表中的一个等待被删除的节点(非表头或表尾).请在在O(1)时间复杂度删除该链表节点. 您在真实的面试中是否遇到过这个题? Yes 样例 给定 1->2->3-> ...

  4. java算法面试题:有数组a[n],用java代码将数组元素顺序颠倒

    package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util.List; ...

  5. 使用Servlet根据浏览器request的get方法获取值,将磁盘中与之对应的json数据删除的方法

    package com.swift; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStrea ...

  6. oracle数据库删除表时遇见需要解锁问题

    今天在进行数据清空时,不注意把表锁住了,记录一下解锁过程. 第一步执行 select t2.username,t2.sid,t2.serial#,t2.logon_time from v$locked ...

  7. Oracle - 存储过程、函数、包的使用练习-雇员

    --存储过程范例:得到雇员表 emp 的记录数 begin --说明:若过程中要向外抛异常,请使用 exception when others then raise; 这个抛出的异常在程序里是可以捕获 ...

  8. 项目实战15.1—企业级堡垒机 jumpserver一步一步搭建

    本文收录在Linux运维企业架构实战系列 环境准备 系统:CentOS 7 IP:192.168.10.101 关闭selinux 和防火墙 # CentOS 7 $ setenforce 0 # 可 ...

  9. docker安装后无法启动问题

    问题报错: Error starting daemon: Error initializing network controller: list bridge addresses failed: no ...

  10. 多页应用 Webpack4 配置优化与踩坑记录

    前言 最近新起了一个多页项目,之前都未使用 webpack4 ,于是准备上手实践一下.这篇文章主要就是一些配置介绍,对于正准备使用 webpack4 的同学,可以做一些参考. webpack4 相比之 ...