博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
牛客网暑期ACM多校训练营(第二场) G transform
阅读量:5796 次
发布时间:2019-06-18

本文共 2584 字,大约阅读时间需要 8 分钟。

题意: 现有n个集装箱摆在一排,每个集装箱有自己的位置x[i]以及现在装有的物品的数量a[i]。现在要在一个位置将这些东西售卖出去,于是需要将产品运送到某一个位置,已知从位置u到位置v运送一个物品需要的体力值是2*abs(u-v);问有体力值消耗不超过T的情况下最多可以售卖多少物品。

做法:首先我们可以知道,因为我们要将所有的物品运送到一个位置,于是运送的这些集装箱的位置一定是一段区间,不会是断开的,为什么呢,你想啊,假设Y代表该集装箱被运了,X代表该集装箱没有被运,M代表终点码头,如果是断开的,例如YYXMYYY,我们将最端点的集装箱不运或者少运几个,取决于X码头的产品数量,无论是哪一种,改为X码头晕倒M码头是不是都比原来的省体力呢。

于是我们已经知道是一段连续的区间了,我们就二分最后售卖的物品的数量,对于每次二分的结果,我们验证的时候就O(n)的跑一遍,以每个结点为左端点,运送mid个物品,体力消耗合不合法即可。需要枚举两遍,分别为左右端点。

具体的一些细节看代码,比如说如何计算体力值什么的。

这里官方题解给的时间复杂度是O(n*log(sum(a[i]))),自我感觉因为每个端点作为左端点的时候我们还要向右跑,具体跑多远取决于数据,估计比这个复杂度高,但是有跳出。

代码如下:

#include
#include
#include
#include
using namespace std;const long long maxn = 500010;long long n; ///n个码头long long T; ///允许的最大的体力值long long x[maxn], a[maxn]; ///分别代表每个集装箱的位置与现有的容量long long sum_num[maxn]; ///记录集装箱容量的前缀和long long sum_T[maxn]; ///记录前i个集装箱的物品全部运到0号节点需要的体力值 这样记录可以O(1)的算出来区间转移的体力值 可以作为一个窍门void init(){ sum_num[0] = 0; sum_T[0] = 0;}void input(){ for(long long i=1; i<=n; i++) { scanf("%lld", &x[i]); } for(long long i=1; i<=n; i++) { scanf("%lld", &a[i]); sum_num[i] = sum_num[i-1]+a[i]; sum_T[i] = sum_T[i-1]+2*a[i]*x[i]; ///将该物品也运到0号点// printf("%lld..%lld...\n" , sum_num[i] , sum_T[i]); }}long long LL(long long l , long long r){ return (sum_T[r]-sum_T[l-1])-(sum_num[r]-sum_num[l-1])*x[l]*2; ///先将这个区间内的东西移动到0点 再减去多移动的x[l]的距离}long long RR(long long l , long long r){ return (sum_num[r]-sum_num[l-1])*x[r]*2-(sum_T[r]-sum_T[l-1]);}bool ok(long long ans){ long long l , r , mid , mid_num; ///这里的l,r,mid不是二分 是枚举左右端点和中点 我们知道一定是把这个区间的货物运送到中点 ///这里的中点指的不是区间位置的中点,指的是货物总量中点所在的位置 mid_num = ans/2+1; ///首先我们来看,左端点一定被全部运送,右端点可以不全部运送 l = r = mid = 1; while( true ) { while(r<=n && (sum_num[r]-sum_num[l-1])
n || mid>n) break; ///枚举到最后的左端点就跳出 long long tmp = (sum_num[r]-sum_num[l-1])-ans; ///确定右端点集装箱剩余多少个物品// printf("%lld...%lld..%lld..%lld..%lld...%lld...%lld...++++\n" , ans , l , r , mid ,RR(l , mid) , LL(mid , r) , 2*tmp*(x[r]-x[mid])); if((RR(l , mid)+LL(mid , r)-2*tmp*(x[r]-x[mid]))<=T) return true; ///RR代表将位置i,j区间内的物品全部移到j位置需要的体力 ///LL代表将位置i,j区间内的物品全部移到i位置需要的体力 l++; } ///接下来我们看右端点一定被全部运送,左端点不一定的情况,同上 l = r = mid = n; while( true ) { while(l>=1 && (sum_num[r]-sum_num[l-1])
l && (sum_num[r]-sum_num[mid-1])

 

转载于:https://www.cnblogs.com/Flower-Z/p/9528057.html

你可能感兴趣的文章
POP-一个点击带有放大还原的动画效果
查看>>
UE4材质是什么样的机制
查看>>
使用QTP录制自带Flight小实例
查看>>
Loadrunner脚本编程(4)-数据类型操作和字符串操作
查看>>
STL 算法
查看>>
分享:Backbone.js 样例站点与入门指南
查看>>
图的基本算法
查看>>
HTML基础(一)
查看>>
boost.circular_buffer简介
查看>>
Database Appliance并非Mini版的Exadata-还原真实的Oracle Unbreakable Database Appliance
查看>>
网页图片缩放(js)
查看>>
如何用Fiddler对Android应用进行抓包
查看>>
iOS为所需要的视图添加模糊效果--UIVisualEffectView
查看>>
HDU-1222 Wolf and Rabbit (欧几里得定理)
查看>>
Camera Calibration 相机标定:原理简介(五)
查看>>
ehcache实例
查看>>
python 匿名函数
查看>>
javascript实现-------------选择排序
查看>>
centOS中VMware Tools 安装
查看>>
oracle中以dba_、user_、v$_、all_、session_、index_开头的常...
查看>>