P8392 BalticOI 2022 Day1 Uplifting Excursion

贪心加动规,好题,这两个甚至完全相反的东西可以融进一道题……

思路

物品较少,贡献较小,体积较小,但总体积巨大。

直接上 \(dp\) 容易把心态搞炸。

我们可以先考虑贪心,使贡献最多还剩 \(m\)。然后考虑背包填满剩下的体积,且 \(i\) 和 \(-i\) (这里的 \(-i\) 是撤销)的物品是不会重复出现在背包中的,如果重复出现了那么肯定不优,所以最多再加入 \(2m\) 个数,背包值域开 \([-m^2,m^2]\)。

为什么这里的贪心加 \(dp\)​ 是正确的呢?

  • 由于贡献相同,贪心选体积最小的物品肯定可以选择最多。

  • 我们在贪心之后进行了 \(dp\) 调整,这个调整是可以反悔减少物品的,也就是我们的 \(f[l]\) 会在体积满足 \(l\)​ 的情况下尽可能多的增加,尽可能少的减少物品,这也是和普通背包的区别。

那么最后我们得出的答案一方面保证了体积肯定符合规定,一方面保证了贪心和动规选出的或是减少的数都是最多或最少的。

实现

我们在一开始可以先加上所有负数状态,后面的正数状态加入时就相当于也选择了负数。

    scanf("%lld%lld",&n,&l);
for(int i=n;i;i--) scanf("%lld",&a[i]),l+=a[i]*i,ans+=a[i];
int t;
scanf("%lld",&t);ans+=t;
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
if(l<0){printf("impossible");return 0;}
for(int i=1;i<=n;i++)
{
if(b[i]*i<=l) l-=b[i]*i,ans+=(b1[i]=b[i]);
else {b1[i]=l/i;ans+=b1[i];l-=b1[i]*i;break;}
}
for(int i=n;i;i--)
{
if(a[i]*i<=l) l-=a[i]*i,ans-=(a1[i]=a[i]);
else {a1[i]=l/i;ans-=a1[i];l-=a1[i]*i;break;}
}

\(a1,b1\) 记录了选择了多少。

背包可以写成函数的形式并使用二进制优化。

void ins(ll s,ll v,ll w)//s ->数量,v ->体积,w ->贡献
{
s=min(s,n*2+1);
if(v>0)
{
int c=1;
for(;c+c<s;c<<=1,v<<=1,w<<=1);
while(1)
{
for(int i=k-v;i>=0;i--) f[i+v]=max(f[i+v],f[i]+w);
s-=c;
if(c==1) break;
c>>=1,v>>=1,w>>=1;
}
if(s>0)
{
v*=s,w*=s;
for(int i=k-v;i>=0;i--) f[i+v]=max(f[i+v],f[i]+w);
}
}
else
{
v=-v;
int c=1;
for(;c+c<s;c<<=1,v<<=1,w<<=1);
while(1)
{
for(int i=v;i<=k;i++) f[i-v]=max(f[i-v],f[i]+w);
s-=c;
if(c==1) break;
c>>=1,v>>=1,w>>=1;
}
if(s>0)
{
v*=s,w*=s;
for(int i=v;i<=k;i++) f[i-v]=max(f[i-v],f[i]+w);
}
}
}

CODE

#include<bits/stdc++.h>
using namespace std; #define ll long long
#define int long long const int maxn=505; ll l,n,m,k,ans;
ll a[maxn],b[maxn],a1[maxn],b1[maxn];
ll f[maxn*maxn*2]; void ins(ll s,ll v,ll w)
{
s=min(s,n*2+1);
if(v>0)
{
int c=1;
for(;c+c<s;c<<=1,v<<=1,w<<=1);
while(1)
{
for(int i=k-v;i>=0;i--) f[i+v]=max(f[i+v],f[i]+w);
s-=c;
if(c==1) break;
c>>=1,v>>=1,w>>=1;
}
if(s>0)
{
v*=s,w*=s;
for(int i=k-v;i>=0;i--) f[i+v]=max(f[i+v],f[i]+w);
}
}
else
{
v=-v;
int c=1;
for(;c+c<s;c<<=1,v<<=1,w<<=1);
while(1)
{
for(int i=v;i<=k;i++) f[i-v]=max(f[i-v],f[i]+w);
s-=c;
if(c==1) break;
c>>=1,v>>=1,w>>=1;
}
if(s>0)
{
v*=s,w*=s;
for(int i=v;i<=k;i++) f[i-v]=max(f[i-v],f[i]+w);
}
}
} signed main()
{
scanf("%lld%lld",&n,&l);
for(int i=n;i;i--) scanf("%lld",&a[i]),l+=a[i]*i,ans+=a[i];
int t;
scanf("%lld",&t);ans+=t;
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
if(l<0){printf("impossible");return 0;}
for(int i=1;i<=n;i++)
{
if(b[i]*i<=l) l-=b[i]*i,ans+=(b1[i]=b[i]);
else {b1[i]=l/i;ans+=b1[i];l-=b1[i]*i;break;}
}
for(int i=n;i;i--)
{
if(a[i]*i<=l) l-=a[i]*i,ans-=(a1[i]=a[i]);
else {a1[i]=l/i;ans-=a1[i];l-=a1[i]*i;break;}
}
m=n*n,k=m*2;
memset(f,0xcf,sizeof(f));
f[m]=0;
for(int i=1;i<=n;i++)
{
if(b1[i]) ins(b1[i],-i,-1);
if(b[i]-b1[i]) ins(b[i]-b1[i],i,1);
if(a1[i]) ins(a1[i],-i,1);
if(a[i]-a1[i]) ins(a[i]-a1[i],i,-1);
}
if(l>m||f[m+l]<-m){printf("impossible");return 0;}
else printf("%lld",ans+f[m+l]);
}

记得全开 long long

P8392 BalticOI 2022 Day1 Uplifting Excursion的更多相关文章

  1. LOJ#2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On

    题目描述 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会.有 N×M 个这样 ...

  2. P6739 [BalticOI 2014 Day1] Three Friends 题解

    目录 写在前面 Solution 何为字符串哈希(可跳过): Code 写在前面 P6739 [BalticOI 2014 Day1] Three Friends 听说这题可以用比较暴力的做法过,比如 ...

  3. luoguP6754 [BalticOI 2013 Day1] Palindrome-Free Numbers

    目录 luoguP6754 [BalticOI 2013 Day1] Palindrome-Free Numbers 简述题意: Solution: Code luoguP6754 [BalticOI ...

  4. P6753 [BalticOI 2013 Day1] Ball Machine

    P6753 [BalticOI 2013 Day1] Ball Machine 题意 给你一个树,每次从根节点放一个求,如果其子节点有空这个球会向下滚,若有多个节点为空则找儿子中以子树内编号的最小值为 ...

  5. P4675 [BalticOI 2016 day1]Park (并查集)

    题面 在 Byteland 的首都,有一个以围墙包裹的矩形公园,其中以圆形表示游客和树. 公园里有四个入口,分别在四个角落( 1 , 2 , 3 , 4 1, 2, 3, 4 1,2,3,4 分别对应 ...

  6. 「JOISC 2022 Day1」京都观光 题解

    Solution 考虑从\((x_1,y_1)\)走到\((x_2,y_2)\)满足只改变一次方向,则容易求出先向南走当且仅当 \[\frac{a_{x_1} - a_{x_2}}{x_1 - x_2 ...

  7. LOJ 一本通一句话题解系列:

    第一部分 基础算法 第 1 章 贪心算法 1):「一本通 1.1 例 1」活动安排:按照结束时间排序,然后扫一遍就可以了. 2):「一本通 1.1 例 2」种树:首先要尽量的往区间重叠的部分种树,先按 ...

  8. 【搜索 ex-BFS】bzoj2346: [Baltic 2011]Lamp

    关于图中边权非零即一的宽度优先搜索 Description 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组 ...

  9. 电路维修 (广搜变形-双端队列bfs)

    # 2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On [题目描述] 有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会 ...

  10. LOJ2632

    题目描述 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会.有  个这样的元件 ...

随机推荐

  1. Linux下编程常用基本命令

    Linux常用命令 基本操作命令 ls命令 ls -l # 列出文件和目录的详细信息 ls -R # 列出所有文件 ls -a # 列出隐藏文件 l;s # 列出 mv命令 mv example.tx ...

  2. R 语言使用

    安装 brew install r --formulae 使用 CLI /opt/homebrew/bin/r # 进入 R 交互式编程界面 GUI GUI 有官方的 R Studio,不过界面我不是 ...

  3. 【Appium】之自动化定位总结

    一.同级定位时,先定位上级 我想定位[必填]框,我先定位[姓名]的同一个上级 self.driver.find_element(MobileBy.XPATH,"//*[contains(@t ...

  4. Kubernetes-19:Prometheus-operator集群监控神器

    Prometheus-operator集群监控 github地址:https://github.com/prometheus-operator/kube-prometheus 具体的Prometheu ...

  5. 一文搞懂 == 、equals和hashCode

    面试的时候,经常会被问到==和equals()的区别是什么?以及我们也知道重写equals()时候必须重新hashCode().这是为什么?既然有了hashCode()方法了,JDK又为什么要提供eq ...

  6. vue源码解析-实现一个基础的MVVM框架

    基本介绍 vue.js采用数据劫持结合发布-订阅模式的方式,通过Object.defineProperty()来劫持各个属性的getter,setter,在数据变动时发布消息给订阅者,触发响应的监听回 ...

  7. EF Core – JSON Column

    前言 SQL Server 支持 JSON, 以前写过一篇介绍 SQL Server – Work with JSON. 但 EF Core 一直没有支持. 直到 EF Core 7.0 才支持. 参 ...

  8. 十种SQL的语法

    一.ORDER BY FIELD()自定义排序逻辑 ORDER BY FIELD(str,str1,...) 自定义排序sql如下: SELECT * from order_diy ORDER BY ...

  9. QT6框架WebEngine模块之WebEngine总体介绍以及WebEngine能做什么?

    QT6框架WebEngine模块之WebEngine总体介绍以及WebEngine能做什么? 简介 本文简略介绍QT6框架WebEngine模块之WebEngine总体介绍以及WebEngine能做什 ...

  10. Vue中防抖和节流 --来自官方文档

    Vue 没有内置支持防抖和节流,但可以使用 Lodash 等库来实现. 如果某个组件仅使用一次,可以在 methods 中直接应用防抖: <script src="https://un ...