当前位置:网站首页>[ACNOI2022]物品
[ACNOI2022]物品
2022-08-01 16:32:00 【OneInDark】
题目
题目背景
当你感到疑惑时,不妨向神明祈祷;神可以回答一切问题。
O n e I n D a r k \sf OneInDark OneInDark:“卷爷为什么这么卷啊?”
O U Y E \sf OUYE OUYE:“没有比这更质朴的快乐了。”
D D G \sf DDG DDG:“天天说别人二次元,有意思没有嘛。”
O U Y E \sf OUYE OUYE:“这难道不令你感到舒适吗?”
最后是『神明三连击』:
c r a s h e d \sf crashed crashed:“哦,忘记给你说了……”
Tiw-Air-OAO \textsf{Tiw-Air-OAO} Tiw-Air-OAO:“你看到的只是表象……”
O U Y E \sf OUYE OUYE:“本质是一样的!”
题目描述
重量为 k ( − m ⩽ k ⩽ m ) k\;(-m\leqslant k\leqslant m) k(−m⩽k⩽m) 的物品有 a k a_k ak 个,求重量和恰为 L L L 的最多物品数,或报告无解。
数据范围与提示
m ⩽ 200 m\leqslant 200 m⩽200 但 ∣ L ∣ ⩽ 1 0 18 |L|\leqslant 10^{18} ∣L∣⩽1018 以及 a k ⩽ 1 0 12 a_k\leqslant 10^{12} ak⩽1012 。
思路
背包问题的最好优化方式是 balance \textit{balance} balance 。这个在子集和问题的论文中有说到。
简单来说,可以让背包重量始终在 L L L 附近徘徊。因此我们可以略去很多无用信息。
与这道题也比较像,考虑我们需要怎样的调整。但套用那样的方法,得不到好的结果,因为权值与重量并不挂钩。
怎么让二者挂钩呢?性价比。所以我们的贪心初解按照性价比排序,然后这题就做完了!然而我就是想不到,悲夫。
完整地说一遍:先做初步转化,将重量为负数的物品先选上,则其权值变为 − 1 -1 −1,即 “退回” 性价比为 − 1 w \frac{-1}{w} w−1 。按照性价比排序,即先选择重量为 1 , 2 , … , m 1,2,\dots,m 1,2,…,m 的物品,再 “退回” 重量为 − m , − ( m − 1 ) , … , − 1 -m,-(m{-}1),\dots,-1 −m,−(m−1),…,−1 的物品。
考虑最优解与其的差距。存在 balance \textit{balance} balance 方式,即总重量在 [ L − m , L + m ] [L{-}m,L{+}m] [L−m,L+m] 内摇摆;若经过若干次操作后,总重量不变,该替换会使得性价比变低(否则贪心初解可以更优),因此是无意义的。
因此前缀和两两不同,即最多有 2 m 2m 2m 次调整。因此调整量不超过 2 m 2 2m^2 2m2,每个物品也只需考虑 2 m 2m 2m 以内的增减变化,拿出来做个部分背包即可。
时间复杂度 O ( m 3 ) \mathcal O(m^3) O(m3),或者二进制分组 O ( m 3 log m ) \mathcal O(m^3\log m) O(m3logm) 。
代码
#include <cstdio>
#include <algorithm> // Almighty XJX yyds!!
#include <cstring> // oracle: ZXY yydBUS!!!
#include <cctype> // rainybunny root of the evil.
#include <cstdint>
using llong = long long;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
# define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
for(; isdigit(c); c=getchar()) a = a*10+(c^48);
return a*f;
}
const int MAXN = 300;
llong posi[MAXN+1], nega[MAXN+1];
const int MAXM = MAXN*(MAXN<<1);
const llong INF = (1ll<<60)-1;
llong dp[MAXM<<1|1];
void knapsack(const int& cnt, int weight, int value){
if(cnt == 0) return;
for(int j=0,w,v; true; ++j){
if((cnt>>j) == 1){
w = weight*(cnt^(1<<j))+weight;
v = value*(cnt^(1<<j))+value;
}
else w = weight<<j, v = value<<j;
if(w < 0) rep(i,-w,MAXM<<1)
dp[i+w] = std::max(dp[i+w],dp[i]+v);
else drep(i,MAXM<<1,w) // positive
dp[i] = std::max(dp[i],dp[i-w]+v);
if((cnt>>j) == 1) break;
}
}
inline int trim(const llong& v){
return v >= (MAXN<<1) ? (MAXN<<1) : int(v);
}
int main(){
int n = readint();
llong L; scanf("%lld",&L);
drep(i,n,1) scanf("%lld",&nega[i]);
llong ans; scanf("%lld",&ans);
rep(i,1,n) scanf("%lld",&posi[i]);
if(L < 0){
// negate everything
rep(i,1,n) std::swap(nega[i],posi[i]);
L = -L;
}
rep(i,1,n) L += nega[i]*i;
std::fill_n(dp,MAXM<<1|1,-INF);
dp[MAXM] = 0; // known
rep(i,1,n){
// greedily use them
llong cnt = std::min(L/i,posi[i]);
L -= i*cnt, ans += cnt;
knapsack(trim(cnt),-i,-1);
knapsack(trim(posi[i]-cnt),i,1);
}
drep(i,n,1){
llong cnt = std::min(L/i,nega[i]);
L -= i*cnt, ans += nega[i]-cnt;
knapsack(trim(cnt),-i,1);
knapsack(trim(nega[i]-cnt),i,-1);
}
if(L < MAXM && ans+dp[L+MAXM] >= 0)
printf("%lld\n",ans+dp[L+MAXM]);
else puts("impossible");
return 0;
}
边栏推荐
猜你喜欢
27英寸横置大屏+实体按键,全新探险者才是安全而合理的做法
[Dark Horse Morning Post] Hu Jun's endorsement of Wukong's financial management is suspected of fraud, which is suspected to involve 39 billion yuan; Fuling mustard responded that mustard ate toenails
Ali's official Redis development specification
第一次改开源中间件keycloak总个结
软测面试如何介绍项目?要做哪些技术准备?
Ant discloses the open source layout of core basic software technology for the first time
MLX90640 红外热成像仪测温模块开发笔记(完整版)
时序数据库在船舶风险管理领域的应用
5年测试,只会功能要求17K,功能测试都敢要求这么高薪资了?
08 spark 集群搭建
随机推荐
05 Doris cluster construction
经验|如何做好业务测试?
阿里官方 Redis 开发规范
MySQL INTERVAL Keyword Guidelines
搭建云计算平台(云计算管理平台搭建)
比对软件-blastN结果详解
夸克网盘资源站
PHP 安全漏洞:会话劫持、跨站点脚本、SQL 注入以及如何修复它们
27英寸横置大屏+实体按键,全新探险者才是安全而合理的做法
【Untitled】
Winform message prompt box helper class
沈腾拯救暑期档
Shell basic function writing
显示为弹出窗口是什么意思(电脑总是弹出广告)
moxa串口服务器配置说明(moxa串口驱动)
A full review of mainstream timed task solutions
Synchronized原理
年化收益高的理财产品
高薪程序员&面试题精讲系列131之Eureka如何实现高可用?自我保护机制是怎么回事?
Ant discloses the open source layout of core basic software technology for the first time