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