思路: 二分
因为对于物品个数打一个前缀和的话,是具有单调性的。 所以可以用二分的思想。在jud函数中借鉴了大佬们的尺取写法。我们可以二分答案,然后jud中枚举左端点,然后可以二分右端点和mid点,可能细节多一些。比较好的一个办法就是尺取的写法。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =500005;
struct node
{
ll x;
ll cnt;
}a[N];
int n;
ll T;
ll prew[N];
ll postw[N];
ll prec[N];
ll postc[N];
bool cmp(node a,node b)
{
return a.x<b.x;
}
ll dis(int i,int j)
{
return abs(a[i].x-a[j].x);
}
void init()
{
for(int i=1;i<=n;i++) prec[i]=prec[i-1]+a[i].cnt;
for(int i=n;i>=1;i--) postc[i]=postc[i+1]+a[i].cnt;
for(int i=1;i<=n;i++) prew[i]=prew[i-1]+prec[i-1]*dis(i,i-1)*2;
for(int i=n;i>=1;i--) postw[i]=postw[i+1]+postc[i+1]*dis(i+1,i)*2;
/*cout<<endl;
for(int i=0;i<=n+1;i++) cout<<prec[i]<<" "; cout<<endl;
for(int i=0;i<=n+1;i++) cout<<prew[i]<<" "; cout<<endl;
for(int i=0;i<=n+1;i++) cout<<postc[i]<<" "; cout<<endl;
for(int i=0;i<=n+1;i++) cout<<postw[i]<<" "; cout<<endl;
*/
}
ll cal_pre(int l,int r){
return prew[r]-prew[l-1]-prec[l-1]*(a[r].x-a[l-1].x)*2;
}
ll cal_suf(int l,int r){
return postw[l]-postw[r+1]-postc[r+1]*(a[r+1].x-a[l].x)*2;
}
bool jud(ll num){
ll num2=num/2+1;
int l=1,r=1,mid=1;
while(1){
while(r<=n && prec[r]-prec[l-1]<num) r++;
while(mid<=n && prec[mid]-prec[l-1]<num2) mid++;
if(r>n || mid>n) break;
ll cc=num-(prec[r-1]-prec[l-1]);
ll s=cal_pre(l,mid)+cal_suf(mid,r-1)+cc*(a[r].x-a[mid].x)*2;
// s == 左半边的花费(个数不够num2 +cc == num2 ) + 右半边的花费 + 右半边cc的花费
if(s<=T) return true;
l++;
}
l=n;r=n;mid=n;
while(1){
while(l>=1 && prec[r]-prec[l-1]<num) l--;
while(mid>=1 && prec[mid]-prec[l-1]<num2) mid--;
if(l<1 || mid<1) break;
ll cc=num-(prec[r]-prec[l]);
ll s=cal_pre(l+1,mid)+cal_suf(mid,r)+cc*(a[mid].x-a[l].x)*2;
// s== 左半边的花费(个数不够num2 +cc==num2) + 右半边的花费 + 左半边cc的花费
if(s<=T) return true;
r--;
}
return false;
}
int main()
{
scanf("%d %lld",&n,&T);
for(int i=1;i<=n;i++) scanf("%lld",&a[i].x);
for(int i=1;i<=n;i++) scanf("%lld",&a[i].cnt);
sort(a+1,a+n+1,cmp);
init();
ll l=1,r=prec[n],mid;
ll ans=-1;
while(l<=r)
{
mid=(l+r)>>1;
//cout<<"mid "<<mid<<endl;
if(jud(mid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%lld\n",ans);
return 0;
}
/*
3 2
1 2 3
2 4 5
*/