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. ECMA Script6 中的 尾调用优化

    在读 <深入理解ES6>一书中,看到有关函数的 "尾调用优化" 章节,特此记录一下 尾调用 指的是 函数作为另一个函数的最后一条语句被调用: function foo ...

  2. Go日志管理库zap

    一.zap介绍 在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能: 1.能够将事件记录到文件中,而不是应用程序控制台. 2.日志切割-能够根据文件大小.时间或间隔等来切割日志文件. ...

  3. Angular 18+ 高级教程 – Naming Conversion

    前言 命名规范对项目维护是很重要的. Angular 对项目的渗透很大的, 必须做好命名规范, 不然会很乱. InjectionToken InjectionToken = UPPER_SNAKE_C ...

  4. CSS – 管理

    前言 CSS 有好几种写法. 它们最终出来的效果是一样的, 区别只是在你如何 "写" 和 "读" 或者说开发和维护. 这已经不是如何"实现" ...

  5. Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数

    title: Nuxt Kit 自动导入功能:高效管理你的模块和组合式函数 date: 2024/9/14 updated: 2024/9/14 author: cmdragon excerpt: 通 ...

  6. 1Panel:一个现代化、开源的 Linux 服务器运维管理面板

    前言 之前有小伙伴问:Linux 服务器运维管理除了宝塔,还有其他值得推荐的管理软件吗?,今天大姚给大家分享一个现代化.开源的 Linux 服务器运维管理面板:1Panel. 项目介绍 1Panel是 ...

  7. Java 之跨docker容器备份数据库

    Java 之跨docker容器备份数据库 摘] java中执行数据库备份,每隔10分钟备份一次,保留四份备份文件,项目在windows系统下运行备份命令没问题.项目采用docker部署后,jar部署在 ...

  8. 算法与数据结构——AVL树(平衡二叉搜索树)

    AVL树 在"二叉搜索树"章节提到,在多次插入和删除操作后,二叉搜索树可能退化为链表.在这种情况下,所有操作的时间复杂度将从O(logn)劣化为O(n). 如下图,经过两次删除节点 ...

  9. Flutter 实现骨架屏

    什么是骨架屏 在客户端开发中,我们总是需要等待拿到服务端的响应后,再将内容呈现到页面上,那么在用户发起请求到客户端成功拿到响应的这段时间内,应该在屏幕上呈现点什么好呢? 答案是:骨架屏 那么什么是骨架 ...

  10. FHQ treap(再见splay------)

    但凡打过平衡树的应该都知道\(\huge{二逼平衡树}\)这道题,抄了两个小时的splay版题解,然后发现了\(\huge\color{maroon}FHQ treap\): $\large\colo ...