题目链接

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

White Cloud placed n containers in sequence on a axes. The i-th container is located at x[i] and there are a[i] number of products in it.
White Rabbit wants to buy some products. The products which are required to be sold must be placed in the same container.
The cost of moving a product from container u to container v is 2*abs(x[u]-x[v]).
White Cloud wants to know the maximum number of products it can sell. The total cost can't exceed T.

输入描述:

The first line of input contains 2 integers n and T(n <= 500000,T <= 1000000000000000000)
In the next line there are n increasing numbers in range [0,1000000000] denoting x[1..n]
In the next line there are n numbers in range[0,10000] denoting a[1..n]

输出描述:

Print an integer denoting the answer.

示例1

输入

2 3
1 2
2 3

输出

4

题意:数轴上有n个集装箱,第i个集装箱位于坐标d[i],有a[i]件货物.现在要把集装箱进行一些移动,求所有货物移动花费不超过T的情况下,最多能把多少个集装箱移动到同一个位置?(在将得到的T/2之后,移动花费计算方式为:从u移动一个货物到v花费为|d[u]-d[v]| )

题解:首先对于给出的所有集装箱货物的数目我们可以知道题目输出的答案一定在[最小的集装箱货物,集装箱货物总和]这个区间内,并且题目给出的数据均在longlong范围内支持我们对数据进行二分答案判断该答案是否可以总花费T内达到.

对于每次二分得到的答案,我们需要在O(n)的时间复杂度内判断出该答案是否能得到,那么我们需要先预处理出2个前缀和:

Sum[maxn];    //sum[i]表示第1~i个集装箱所有货物数总和
             F[maxn];    //   f[i]   表示第1~i个集装箱的所有货物移到x=0处所需费用

对于每次判断二分得到的答案(下面统称:需求货物量)是否正确,下面代码写的是一个OK()函数,该函数主要思想是通过维护一个区间,确保这个区间内货物的总和大于等于需求货物量,然后通过移动u指针找到该区间内的最优货物集中点,若是将货物移动到最优货物集中点使得该点货物量满足需求且所需的费用小于等于T,说明该点满足条件(即该需求货物量能达到)

至于为什么在函数内需要进行2个时间复杂度为O(n)的计算操作,第一个while()是从1开始维护区间的,且当区间[L,R]内的货物总和大于X的,我们优先取最左边的货物,且区间逐渐向右移动,直到得到满足条件的情况或者后面区间货物了总和不可能达到要求结束循环;第二个while()是从n开始维护区间的,且当区间[L,R]内的货物总和大于X的,我们优先取最右边的货物,且区间逐渐向左移动,

:为什么都是优先取边界的(即优先放弃离最优货物集中点最远的点,那么这个点只能是L或者R),若是第一个while循环选择优先放弃R的不是最优,第二个while循环也能补上,只要保证我们能在有限时间内判断出该需求货物量能在花费T内达到就行~

至于2个cnt函数是2个while内部的计算,即2种优先取法下,将[L,R]中货物集中到 i 处使之货物量达到需求货物量所需的费用.

计算如下:(其中x为需求货物量)

费用=将区间L+1~i中所有货物移动到i处所需的费用 + 将区间i+1~R中所有的货物移动到i处所需的费用

- 区间L+1~R比x多的货物数从R处移动到i处的费用)

下面介绍下如何使用前缀和的方法O(1)计算出区间内货物移动所需的费用:(举CNT_1函数的例子)

(如果看不懂我代码的CNT函数可以考虑看下面内容自己手推,代码是自己手推的=.=)

F[i]-F[L] 可以通俗的表示为将L+1~i 中的所有货物移动到x=0处获得的费用(没错,就是获得)

(sum[i]-sum[L])*d[i] 表示为将L+1~i处的货物全部从x=0处移动到d[i]所消耗的费用(这里才是消耗)

那么 (sum[i]-sum[L])*d[i]   -   ( F[i]-F[L] )  就是将区间[L+1,R]中L+1~i 内的所有货物移动 i 处所消耗的费用

不过对于将i+1~R区间的货物移动到i处所需的费用需要反过来减(思考一下就明白原因了~)

所以将i+1~R中所有的货物移动到i处所需的费用为:   (f[R] - f[i]) - (sum[R] - sum[i])*d[i]

对于  sum[R] - sum[L] - q 则是计算出区间[L,R]的货物总量比q=x多出的部分,按照当前是优先放弃R的原则我们可以知道:

区间L+1~R比x多的货物数从R处移动到i处的费用(sum[R] - sum[L] - q)*(d[R] - d[i])

至于另外一个优先放弃左边界(L)的CNT_2函数自己推敲~(原理就是上面那样了)

代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const int maxn = 5e5 + 10;
ll d[maxn];      //d[i]表示第i个集装箱距离x=0的距离
ll a[maxn];      //a[i]表示第i个集装箱有的货物个数
ll sum[maxn];    //sum[i]表示第1~i个集装箱有的货物数总和
ll f[maxn];      //f[i]表示第1~i个集装箱的所有货物移到x=0处所需费用
ll t, q;
int n, L, R, u;  //u为货物汇总的最优点
ll cnt_1(int i) {//费用=将L+1~i中所有货物移动到i处所需费用+(将i+1~R中所有的货物移动到i处所需的费用 - 区间L+1~R比x多的货物数从R处移动到i处的费用)return ((sum[i] - sum[L])*d[i] - (f[i] - f[L])) + ((f[R] - f[i]) - (sum[R] - sum[i])*d[i] - (sum[R] - sum[L] - q)*(d[R] - d[i]));
}
ll cnt_2(int i) {//同上,只是规则是优先从右边界开始取货物return -((sum[R] - sum[i])*d[i] - (f[R] - f[i])) - ((f[i - 1] - f[L]) - (sum[i - 1] - sum[L])*d[i] + (sum[R] - sum[L] - q)*(d[i] - d[L + 1]));
}
bool ok(ll x) {                                //判断需求x是否能在所给的费用t内达到q = x;              L = 0, R = 1, u = 1; while (1) {                                //从左边界开始向右移动区间,优先取区间左边的货物while (R < n&&sum[R] - sum[L] < x) R++;if (sum[R] - sum[L] < x)break;         //若是当前的L~n无法满足x,那么L++也不可能满足while (u < L)u++;                      //将u移动到当前区间的起点while (u < R&&cnt_1(u)>cnt_1(u + 1))u++;if (cnt_1(u) <= t)return true;L++;}L = n - 1, R = n, u = n;while (1) {                                //从右边界开始向左移动区间,优先取区间右边的货物while (L > 0 && sum[R] - sum[L] < x) L--;if (sum[R] - sum[L] < x)break;         //若是当前的L~R无法满足x,那么R--也不可能满足while (u > R)u--;while (u > L && cnt_2(u) > cnt_2(u - 1))u--;if (cnt_2(u) <= t)return true;R--;}return false;
}
int main()
{scanf("%d%lld", &n, &t);t /= 2;for (int i = 1; i <= n; i++)scanf("%lld", &d[i]);for (int i = 1; i <= n; i++) {  //输出和前缀和预处理scanf("%lld", &a[i]);sum[i] = sum[i - 1] + a[i];f[i] = f[i - 1] + a[i] * d[i];}ll l = 0,r = sum[n] + 1;while (l + 1 < r) {              //二分答案ll mid = (l + r) >> 1;if (ok(mid)) l = mid;else r = mid;}printf("%lld\n", l);return 0;
}

牛客网暑期ACM多校训练营(第二场)G.transform (二分+思维)相关推荐

  1. 牛客网暑期ACM多校训练营(第二场):J. farm(暴力)

    链接:https://www.nowcoder.com/acm/contest/140/J 来源:牛客网 题目描述 White Rabbit has a rectangular farmland of ...

  2. 2018牛客网暑期ACM多校训练营第二场 D - money(贪心)

    题目链接 https://www.nowcoder.com/acm/contest/140#question [题目描述] White Cloud is exercising in the playg ...

  3. 牛客网暑期ACM多校训练营(第十场)F.Rikka with Line Graph

    牛客网暑期ACM多校训练营(第十场)F.Rikka with Line Graph 做法:\(G'\) 中的对应原图两条边(a,b) (c,d)的最短路为: \[ w[a][b] + w[c][d] ...

  4. 牛客网暑期ACM多校训练营(第九场)

    牛客网暑期ACM多校训练营(第九场) A. Circulant Matrix 做法:看到下标 \(xor\) 这种情况就想 \(FWT\),可是半天没思路,于是放弃了..其实这个 \(n\) 疯狂暗示 ...

  5. 牛客网暑期ACM多校训练营(第五场)

    牛客网暑期ACM多校训练营(第五场) A. gpa 二分答案,然后就转化为是否满足 \(\frac {\sum s[i]c[i]}{\sum s[i]} ≥ D\), \(\sum s[i]c[i] ...

  6. 牛客网暑期ACM多校训练营(第三场)

    牛客网暑期ACM多校训练营(第三场) A. PACM Team 01背包,输出方案,用bool存每种状态下用的哪一个物品,卡内存.官方题解上,说用char或者short就行了.还有一种做法是把用的物品 ...

  7. 牛客网暑期ACM多校训练营(第一场)

    牛客网暑期ACM多校训练营(第一场) A. Monotonic Matrix 考虑0和1的分界线,1和2的分界线,发现问题可以转化为两条不互相穿过的路径的方案数(可重叠),题解的做法就是把一条路径斜着 ...

  8. 牛客网暑期ACM多校训练营(第十场)D Rikka with Prefix Sum

    链接:https://www.nowcoder.com/acm/contest/148/D 来源:牛客网 题目描述 Prefix Sum is a useful trick in data struc ...

  9. 牛客网暑期ACM多校训练营(第三场)A.PACM Team(多重01背包)

    链接:https://www.nowcoder.com/acm/contest/141/A 来源:牛客网 题目描述 Eddy was a contestant participating in ACM ...

  10. 2018牛客网暑期ACM多校训练营(第十场)A Rikka with Lowbit (树状数组)

    链接:https://ac.nowcoder.com/acm/contest/148/A 来源:牛客网 Rikka with Lowbit 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C ...

最新文章

  1. 日期格式转换 java 2016-09-03T00:00:00.000+08:00
  2. HashMap 为什么会导致 CPU 100%?文章看不懂?
  3. golang Receiver has generic name 问题解决
  4. 使用Spring Cloud Function框架进行面向函数的编程
  5. linux系统用户组管理
  6. (精华)转:RDD:创建的几种方式(scala和java)
  7. 给楠哥准备的入门单片机
  8. 有关emoji表情以及utf-16编码
  9. SQL Server中的假期表和GetWorkDays函数
  10. 锁定计算机好在下游戏吗,巧用win7锁定计算机防止孩子沉迷游戏
  11. GDAL 2.0版本RPC校正速度测试
  12. oracle如何储存超长汉子_厦门到惠州整车运输超长超宽超重运输
  13. 厦门理工学院计算机毕业要求,计算机教学中心-厦门理工学院教务处.PDF
  14. java事务传播机制事例,spring事务传播机制
  15. 三菱FX+GS2107无序组合程序,说明:任意点击触摸屏1-15工位
  16. vue给标签动态添加元素_vue中用v-html加载html元素及三种方法给v-html元素添加样式(详解)...
  17. QCC512X--QCC514X--QCC302X--QCC304X烧录工具
  18. SCRAPY爬虫实例
  19. 利用RunLoop空闲时间执行预缓存任务
  20. Google搜索API?

热门文章

  1. 2021年软件开发趋势大预测
  2. SPDK Delay Bdev 介绍及应用实例
  3. WPS文档出现很多小箭头解决
  4. php 抓取淘宝商品详情
  5. 使用IE浏览器,禁止访问,显示 Internet Explorer增强安全配置正在阻止来自下列网站的从应用程序中的内容
  6. [Win10+Excel365]尽管已启用VBA宏,Excel还是无法运行宏
  7. 《护理教育学》名词解释、简答题、问答题汇总
  8. 公共场所的标志和说明英文表达100例
  9. Win10电脑用360杀毒一全盘杀毒就蓝屏
  10. NIPS大会最精彩一日:AlphaZero遭受质疑;史上第一场正式辩论与LeCun激情抗辩;元学习强化学习亮点复盘...