牛客多校第二场 G(二分)

链接:https://www.nowcoder.com/acm/contest/140/G
来源:牛客网
 

时间限制: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

 

二分答案

对于每个i为左端点的区间,他的最远的r跟所有货物移动到的位置mid都是可以求出来的‘

对于i+1为左端点的区间,他的r和mid一定是>=i的r跟mid的。

#include<bits/stdc++.h>
#define mp make_pair
#define fir first
#define se second
#define ll long long
#define pb push_back
using namespace std;
const int maxn=5e5+10;
const ll mod=1e9+7;
const int maxm=1e6+10;
const double eps=1e-7;
const ll inf=(ll)1e13;
ll x[maxn],w[maxn];
ll prew[maxn],precost[maxn],sufw[maxn],sufcost[maxn];
int n;
ll t;
ll call(int l,int r){
    return precost[r]-precost[l-1]-prew[l-1]*(x[r]-x[l-1]);
    //[l,r]内的花费=移动[1,r]的花费-移动[1,l]的花费-[1,l]移动到r的花费
}
ll calr(int l,int r){
    return sufcost[l]-sufcost[r+1]-sufw[r+1]*(x[r+1]-x[l]);
    //与上面一个类似
}
int check(ll mid){
    int l=1,r=2,Mid=2;
    ll num=mid/2+1;
    while (1){
        while (r<=n&&prew[r]-prew[l-1]<mid) r++;
        while (Mid<=n&&prew[Mid]-prew[l-1]<num) Mid++;
        if (r>n||Mid>n) break;
        if (call(l,Mid)+calr(Mid,r-1)+(mid-(prew[r-1]-prew[l-1]))*(x[r]-x[Mid])<=t)
            return 1;
        l++;
    }
    l=n-1;
    r=n;
    Mid=n;
    while (1){
        while (l>=1&&prew[r]-prew[l-1]<mid) l--;
        while (Mid>=2&&prew[Mid]-prew[l-1]<num) Mid--;
        if (l<1||Mid<2) break;
        
        if (call(l+1,Mid)+calr(Mid,r)+(mid-(prew[r]-prew[l]))*(x[Mid]-x[l])<=t)
            return 1;
        r--;
    }
    return 0;
}
int main(){
    scanf("%d %lld",&n,&t);
    t/=2;
    for (int i=1;i<=n;i++){
        scanf("%lld",&x[i]);
    }
    for (int i=1;i<=n;i++){
        scanf("%lld",&w[i]);
    }
    for (int i=1;i<=n;i++){
        prew[i]=prew[i-1]+w[i];
        precost[i]=precost[i-1]+(x[i]-x[i-1])*prew[i-1];
        //移动到当前位置的花费=移动到I-1的花费+把这些都移动到i的花费
    }
    for (int i=n;i>=1;i--){
        sufw[i]=sufw[i+1]+w[i];
        sufcost[i]=sufcost[i+1]+(x[i+1]-x[i])*sufw[i+1];
        //与上一个类似
    }
    ll sum=0;
    for (int i=1;i<=n;i++)
        sum+=w[i];
    ll l=0;
    ll r=sum;
    while (r-l>1){
        ll mid=(l+r)>>1;
        if (check(mid)){
            l=mid;
        }
        else r=mid-1;
    }
    if (check(max(r,l))){
        printf("%lld\n",max(r,l));
    }
    else{
        printf("%lld\n",min(r,l));
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值