牛客网暑期多校训练第二场G题

链接: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

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

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=5e5+7;
const int INF=0x3f3f3f3f;
int n;
ll t;
ll x[maxn];
ll a[maxn];
ll sum1[maxn];
ll sum2[maxn];
ll s1(int x,int y){return sum1[max(y,x)]-sum1[min(y,x)-1];}
ll s2(int x,int y){return sum2[max(y,x)]-sum2[min(y,x)-1];}
bool check(ll k)//检查能否取到k
{
    int l=1,r=1,m=1;//左端点,右端点,中点
    //从左到右扫一遍
    while(l<=n&&r<=n&&m<=n)
    {
        while(r=k&&x[m]*s1(l,m)-s2(l,m)+s2(r,m)-x[m]*s1(r,m)-(s1(r,l)-k)*(x[r]-x[m])<=t)return 1;
    //总的个数大于k   移动l-m的消耗        移动m-r的消耗           减去加上a[r]比k多的个数的消耗    总的消耗比t小
        l++;
    }
    l=r=m=n;
    //从右到左扫一遍
    while(l>=1&&r>=1&&m>=1)
    {
        while(l>1&&s1(l,r)1&&2*s1(m,r)=k&&x[m]*s1(l,m)-s2(l,m)+s2(r,m)-x[m]*s1(r,m)-(s1(r,l)-k)*(x[m]-x[l])<=t)return 1;
        r--;
    }
    return false;
}
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",&a[i]);
    for(int i=1;i<=n;++i)
       {
           sum1[i]=sum1[i-1]+a[i];
           sum2[i]=sum2[i-1]+a[i]*x[i];
       }
    ll l=1;
    ll r=sum1[n];
    ll ans;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(check(mid))
        {
            l=mid+1;
            ans=mid;
        }
        else r=mid-1;
    }
    printf("%lld\n",ans);
}

 

你可能感兴趣的:(二分,三分)