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

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

输入
2 3
1 2
2 3
输出
4

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

思路:官方说:因为我们要让货物移动总距离尽可能小,所以最后所使用的集装箱的初始位置在数轴上一定是一段区间。 如果固定了这个区间,而这段区间中从左到右满足距离之和先减后增。然后O(n)尺取法前后枚举一边区间就可以了。

一下来自:https://blog.csdn.net/LSD20164388/article/details/81152298

解析:

s[i]表示前i个位置有多少个桶,t[i]表示前i个位置的所有桶从0坐标移动过来的距离和。

假设我们二分到可以搬x个桶到同一个位置,当前判断的连续区间为[lp+1,rp],则首先s[rp]-s[lp]>=x。此时会有两种情况,就是我们在这个区间内要挑出x个桶。显然多余的桶一定在a[rp]或者在a[lp](因为我们单调枚举左端点)。当在a[rp]时,我们就不需要搬那多余的(s[rp]-s[lp]-x)个桶了。于是我们枚举这x个桶搬到某个位置x[i]时,区间下标[lp+1,i]的桶搬到x[i]的总距离为:

(s[i]-s[lp])*d[i]-(t[i]-t[lp]);

区间下标[i,rp]的桶搬到x[i]的总距离为(除去多余的桶和上一步已经搬了的桶):

t[rp]-t[lp]-(s[rp]-s[lp]-x)*d[i]-(t[i]-t[lp])-(x-(s[i]-s[lp]))*d[i];

以上式子需要好好思考一下。

当在a[lp]时与以上情况类似。此时需要从右往左枚举区间右端点。

具体处理的意思看代码吧

代码:

#include<bits/stdc++.h>
#define maxn 500050
  
using namespace std;
typedef long long ll;
ll s[maxn],t[maxn],l,r,mid,n,a[maxn],d[maxn],k,c,lp,rp,mp,w,o,p;
  
ll c1(ll x){//前两个式子表示lp到x的箱子都从相应的位置搬到x的总距离,后两个式子表示从x到rp的箱子从相应的位置搬到x点的总距离
    return (s[x]-s[lp])*d[x]-(t[x]-t[lp])+(o-t[x]+t[lp])-(p-s[x]+s[lp])*d[x];
}
  
ll c2(ll x){
    return (t[rp]-t[x])-(s[rp]-s[x])*d[x]+(p-s[rp]+s[x])*d[x]-(o-t[rp]+t[x]);
}
  
bool check(ll x){
    p=x;
    lp=0; rp=1; mp=1;
    while (1){
        while (rp<n&&s[rp]-s[lp]<x) rp++;
        if (s[rp]-s[lp]<x) break;
        o=t[rp]-t[lp]-(s[rp]-s[lp]-x)*d[rp];//除去rp上多的,剩下从lp到rp的x个箱子搬到相应位置的总距离
        while (mp<n&&c1(mp)>c1(mp+1)) mp++;
        if (c1(mp)<=c) {
            return true;
        }
        lp++;
    }
    lp=n-1; rp=n; mp=n;
    while (1){
        while (lp&&s[rp]-s[lp]<x) lp--;
        if (s[rp]-s[lp]<x) break;
        o=t[rp]-t[lp]-(s[rp]-s[lp]-x)*d[lp+1];
        while (mp>1&&c2(mp)>c2(mp+1)) mp--;
        if (c2(mp)<=c) {
            return true;
        }
        rp--;
    }
    return false;
}
  
int main()
{
    scanf("%lld%lld",&n,&c);
    c/=2;
    for (int i=1;i<=n;i++) scanf("%lld",&d[i]);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i],t[i]=t[i-1]+a[i]*d[i];
    l=0; r=s[n]+1;
    while (r-l>1){
        mid=(l+r)/2;
        if (check(mid)) l=mid; else r=mid;
    }
    cout << l << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/snayf/article/details/81161903