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. 平衡搜索树-AVL树 图文详解 (万字长文)

    目录 AVL树 AVL树的概念 AVL树节点的定义: AVL树的插入 基本情况分析 平衡因子对应的操作 旋转操作 分析需要旋转的情况 结论 4种旋转操方法与特征 6种双旋平衡因子特征 代码实现 四种旋 ...

  2. 学习redis问题记录

    2024年5月25日 倒腾了很长时间 突然发现的问题 ide提示改为toList() 我顺便就改过去了 但是实际业务中redis序列化会产生无法反序列化的问题 造成缓存挂壁 业务直接G collect ...

  3. Python批量分割Excel后逐行做差、合并文件的方法

      本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,基于其中每一个文件,首先依据某一列数据的特征截取我们需要的数据,随后对截取出来的数据逐行求差,并基于其他多个文件夹中同样大量 ...

  4. Go runtime 调度器精讲(六):非 main goroutine 运行

    原创文章,欢迎转载,转载请注明出处,谢谢. 0. 前言 在 Go runtime 调度器精讲(三):main goroutine 创建 介绍了 main goroutine 的创建,文中我们说 mai ...

  5. MyBatis——案例——添加

    添加   1.编写接口方法:Mapper接口     参数:除了 id 之外的所有数据     结果:void /** * 添加 */ void add(Brand brand);   2.编写SQL ...

  6. Java项目笔记(二)

    一.分页待解决的问题 分页是在service层实现的 在controller层和service层同时写了这句代码 PageHelper.startPage(Integer.valueOf(pageNo ...

  7. 【赵渝强老师】Oracle的PGA与数据库连接建立的过程

    首先,我们来了解一下Oracle的内存结构,如下: 关于Oracle的内存结构,详情请查看:[赵强老师]Oracle数据库的内存结构 (一)PGA的组成结构 PGA主要由以下三部分组成: 私有SQL区 ...

  8. ArkTS 和仓颉的特性对比与案例

    ArkTS和仓颉是两种不同的编程语言,它们各自具有独特的特性和设计目的. ArkTS特性 ArkTS是一种基于TypeScript的编程语言,专门为鸿蒙应用开发而设计.它保留了TypeScript的大 ...

  9. .net 泛型 Generic

    什么是泛型 就是不确定的类型

  10. Promise 有几种状态,什么时候会进入catch?

    Promise 有几种状态 三个状态:pending.fulfilled.reject 两个过程:padding -> fulfilled.padding -> rejected Prom ...