当前位置: 代码迷 >> 综合 >> 重新填坑——牛客暑期多校第二场 G Transform(二分+预处理)
  详细解决方案

重新填坑——牛客暑期多校第二场 G Transform(二分+预处理)

热度:60   发布时间:2023-12-22 14:21:12.0

这道题的思路:

预处理出物品个数的前缀和、后缀和,以及 将1到i-1位置的物品全部搬到i位置的花费和 与 将n到n-i+1的物品全部搬到i位置的花费和,然后对要求的物品个数二分答案。

check的时候,因为物品个数确定,枚举左端点,左端点位置确定的时候右端点位置和中间值位置也确定,因此可以通过预处理的东西直接计算出全部搬到中间值位置的花费。

但是对于为什么只需要求左端点的箱子都取、右端点在的箱子取部分 和 右端点在的箱子都取、左端点在的箱子取部分就能得到最小花费我还无法理解。。。(纠结了很久了,就是想不清楚= =)

 

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define m_p make_pair
#define p_b push_back
#define For(i,a,b) for(int i=a;i<=b;i++)
#define ls (root<<1)
#define rs ((root<<1)|1)
const int N=5e5;
const int M=1e4+5;
const db eps=1e-8;
const int INF=0x3f3f3f3f;
const int mod=1e7;
int n;
struct node{ll x,a;bool operator<(const node &p)const{return x<p.x;}
}a[N+5];
ll T,s[N+5],s1[N+5],pre[N+5],nex[N+5];
bool check(ll num){ll lpos=1,rpos=1,mid=1;ll num1=(num+1)/2;while(rpos<=n&&mid<=n){while(rpos<=n&&s[rpos]-s[lpos-1]<num){rpos++;}if(rpos>n) break;while(mid<=n&&s[mid]-s[lpos-1]<num1) mid++;if(mid>n) break;ll res=pre[mid]-pre[lpos]-2*s[lpos-1]*(a[mid].x-a[lpos].x);res+=nex[mid]-nex[rpos-1]-2*s1[rpos]*(a[rpos-1].x-a[mid].x);res+=2*(num-(s[rpos-1]-s[lpos-1]))*(a[rpos].x-a[mid].x);if(res<=T) return 1;lpos++;}rpos=n,mid=n,lpos=n;while(lpos>=1&&mid>=1){while(lpos>=1&&s1[lpos]-s1[rpos+1]<num) lpos--;if(lpos<1) break;while(mid>=1&&s1[mid]-s1[rpos+1]<num1) mid--;if(mid<1) break;ll res=pre[mid]-pre[lpos+1]-2*s[lpos]*(a[mid].x-a[lpos+1].x);res+=nex[mid]-nex[rpos]-2*s1[rpos+1]*(a[rpos].x-a[mid].x);res+=2*(num-(s[rpos]-s[lpos]))*(a[mid].x-a[lpos].x);if(res<=T) return 1;rpos--;}return 0;
}
int main(){
//  freopen("in.txt","r",stdin);scanf("%d %lld",&n,&T);For(i,1,n) scanf("%lld",&a[i].x);For(i,1,n) scanf("%lld",&a[i].a);sort(a+1,a+1+n);ll l=1,r=0,mid,ans=0;For(i,1,n) r+=a[i].a,s[i]=r,pre[i]=2*s[i-1]*(a[i].x-a[i-1].x)+pre[i-1];for(int i=n;i>=1;i--) s1[i]=s1[i+1]+a[i].a,nex[i]=nex[i+1]+2*s1[i+1]*(a[i+1].x-a[i].x);while(l<=r){mid=(l+r)>>1;if(check(mid)) l=mid+1,ans=mid;else r=mid-1;}cout<<ans<<"\n";return 0;
}