牛客网暑期ACM多校训练营(第二场)G transform

题目大意:
数轴上有n个集装箱,第i个集装箱位于坐标x[i],有a[i]件货物。现在要把集装箱进行一些移动,求在所有货物移动总距离不超过T的情况下,最多能把多少个集装箱移动到同一个位置
 

做法:
因为我们要让货物移动总距离尽可能小,所以最后所使用的集装箱的初始位置在数轴上一定是一段区间。如果固定了这个区间,那么最优方案就是把这些集装箱移动到这些集装箱的坐标中位数的位置。答案满足可二分性,先二分答案。然后我们按照从左至右的顺序枚举区间的中位数位置,那么区间的左端点和右端点都是单调递增的,一遍枚举一遍维护即可。
复杂度O(n*log(sum(a[i]))) (差不多参考了官方题解)
 

代码:

#include<bits/stdc++.h>
#define N 500005
#define P pair<int,int>
using namespace std;
typedef long long ll;
const int M=1e9+7;
const int inf=1e9+7;
int a[N],n,b[N];
ll x[N],pre[N],T;
bool check(ll need)
{
    int l=1,r=2;
    ll lsum=a[1],rsum=0,c=0;
    memcpy(b,a,sizeof(a));
    b[1]=0;
    while(lsum+rsum<=need&&r<=n){
        ll res=min((ll)a[r],need-lsum-rsum);
        rsum+=res;
        c+=(x[r]-x[1])*res;
        b[r]-=res;
        if(!b[r])r++;
        if(lsum+rsum>=need)break;
    }
    if(c<=T)return 1;
    for(int i=2;i<=n;i++){
        c+=(lsum-rsum)*(x[i]-x[i-1]);
        lsum+=a[i]-b[i];
        rsum-=a[i]-b[i];
        while(r<=n&&x[r]-x[i]<x[i]-x[l]){
            ll tmp=min(b[r],a[l]-b[l]);
            c+=tmp*(x[r]-x[i]-x[i]+x[l]);
            b[l]+=tmp;lsum-=tmp;
            b[r]-=tmp;rsum+=tmp;
            if(b[l]==a[l])l++;
            if(!b[r])r++;
        }
        if(c<=T)return 1;
    }
    return 0;
}
int main()
{
    scanf("%d%lld",&n,&T);
    T/=2;
    for(int i=1;i<=n;i++)
        scanf("%lld",&x[i]);
    ll l=0,r=pre[n];
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        r+=a[i];
    }
    while(l<=r)
    {
        ll m=l+r>>1;
        if(check(m))l=m+1;
        else r=m-1;
    }
    printf("%lld\n",r);
    return 0;
}
/*
3 26
1 3 6
5 5 5
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值