牛客网暑期ACM多校训练营(第二场) transfrom(二分+尺取)

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

题目描述
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

思路:

首先可以确定的是所需要移动的物品位置是一段连续区间,把每个位置的物品单独拿出来看成一个单独的物品,那么明显的就是要移动到中点位置,那么我们只要知道了区间左端点,右端点就可以知道中点的位置(就是sum>=need/2)的位置,左端点我们可以枚举,右端点自然不能枚举,那么我们可以二分最终的答案,就可以通过所需要的数量知道右端点的位置,而且是递增的
所以这是个O(n)的过程,知道了左端点,右端点,中点,自然就能O(1)算出花费,非常简单的公式,随手推就行,另外需要注意的就是但数量为偶数的时候中点可能是在两个位置点的,这时候我们正着扫一遍,反着扫一遍就行了

accode

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn =5e5+23;
int n;
LL T;
LL sum1[maxn];
LL sum2[maxn];
LL cnt[maxn];
LL pos[maxn];
int check(LL need)
{
    int mid = 1;
    int r = 1;
    for(int l = 1; l<=n; l++)
    {
        while(r<=n&&sum1[r]-sum1[l-1]<need)
        {
            r++;
        }
        if(r>n) break;
        while(mid<=r&&sum1[mid]-sum1[l-1]<(need-1)/2+1)
        {
            mid++;
        }

        if(mid>r) break;
        LL sum = 2*(pos[mid]*(sum1[mid-1]-sum1[l-1])-(sum2[mid-1]-sum2[l-1]))+2*((sum2[r]-sum2[mid])-pos[mid]*(sum1[r]-sum1[mid]));
        LL ttt = sum;
        if(sum<=T)
        {
            return 1;
        }
        LL tmpsum = sum1[r]-sum1[l-1];
        LL s  = tmpsum-need;
        if(s<=cnt[l])
        {
            sum -= 2*(pos[mid]-pos[l])*s;
            if(sum<=T)
            {
                return 1;
            }
        }
        else
        {
            sum -= 2*(pos[mid]-pos[l])*cnt[l];
            s-=cnt[l];
            if(sum<=T)
            {
                return 1;
            }
            if(cnt[r]>=s)
            {
                sum -= 2*(pos[r]-pos[mid])*s;
                if(sum<=T)
                {
                    return 1;
                }
            }
        }
        tmpsum = sum1[r]-sum1[l-1];
        s  = tmpsum-need;
        sum = ttt;
        if(s<=cnt[r])
        {
            sum -= 2*(pos[r]-pos[mid])*s;
            if(sum<=T)
            {
                return 1;
            }
        }
        else
        {
            sum -= 2*(pos[r]-pos[mid])*cnt[r];
            s-=cnt[r];
            if(sum<=T)
            {
                return 1;
            }
            if(cnt[l]>=s)
            {
                sum -= 2*(pos[mid]-pos[l])*s;
                if(sum<=T)
                {
                    return 1;
                }
            }
        }
    }
    int l = n;
    mid = n;
    for(int i = n; i>=1; i--)
    {
        r = i;
        while(l>=1&&sum1[r]-sum1[l-1]<need)
        {
            l--;
        }
        if(l<1) break;
        while(mid>=l&&sum1[r]-sum1[mid-1]<(need-1)/2+1)
        {
            mid--;
        }
        if(mid<l) break;
        LL sum = 2*(pos[mid]*(sum1[mid-1]-sum1[l-1])-(sum2[mid-1]-sum2[l-1]))+2*((sum2[r]-sum2[mid])-pos[mid]*(sum1[r]-sum1[mid]));
        LL ttt = sum;
        if(sum<=T)
        {
            return 1;
        }
        LL tmpsum = sum1[r]-sum1[l-1];
        LL s  = tmpsum-need;
        if(s<=cnt[l])
        {
            sum -= 2*(pos[mid]-pos[l])*s;
            if(sum<=T)
            {
                return 1;
            }
        }
        else
        {
            sum -= 2*(pos[mid]-pos[l])*cnt[l];
            s-=cnt[l];
            if(sum<=T)
            {
                return 1;
            }
            if(cnt[r]>=s)
            {
                sum -= 2*(pos[r]-pos[mid])*s;
                if(sum<=T)
                {
                    return 1;
                }
            }
        }
        tmpsum = sum1[r]-sum1[l-1];
        s  = tmpsum-need;
        sum = ttt;
        if(s<=cnt[r])
        {
            sum -= 2*(pos[r]-pos[mid])*s;
            if(sum<=T)
            {
                return 1;
            }
        }
        else
        {
            sum -= 2*(pos[r]-pos[mid])*cnt[r];
            s-=cnt[r];
            if(sum<=T)
            {
                return 1;
            }
            if(cnt[l]>=s)
            {
                sum -= 2*(pos[mid]-pos[l])*s;
                if(sum<=T)
                {
                    return 1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d%lld",&n,&T);
    LL r = 0;
    for(int i = 1; i<=n; i++)
    {
        scanf("%lld",&pos[i]);
    }
    for(int i = 1; i<=n; i++)
    {
        scanf("%lld",&cnt[i]);
        r+=cnt[i];
    }
    for(int i = 1; i<=n; i++)
    {
        sum1[i] = sum1[i-1]+cnt[i];
        sum2[i] = sum2[i-1]+(cnt[i]*pos[i]);
    }
    LL l = 0;
    LL ans = 0;
    while(l<=r)
    {
        LL mid = (l+r)>>1;
        if(check(mid))
        {
            l = mid+1;
            ans = max(ans,mid);
        }
        else
        {
            r = mid-1;
        }
    }
    cout<<ans<<endl;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值