1. 程式人生 > >牛客網2018暑期ACM多校訓練營(第二場)G transform 尺取法 帶權中位數

牛客網2018暑期ACM多校訓練營(第二場)G transform 尺取法 帶權中位數

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL mod=1e9+7;
const int maxn=5e5+10;
int n;LL t;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    
return x*f; } LL x[maxn],a[maxn],s[maxn]; //給定n個容器的位置xi和每個容器內部的物品個數ai,每個物品移動的代價是|xi-xj|,可承受的最大代價T
//求最多能把多少個物品集中到一個容器內
int main() { #ifdef shuaishuai freopen("in.txt","r",stdin); #endif // shuaishuai scanf("%d%lld",&n,&t); for(int i=1;i<=n;i++) x[i]=read(); for(int j=1;j<=n;j++) a[j]
=read(), s[j]=a[j]+s[j-1]; LL l=1,r=1,m=1,ans=0; t/=2;
//首先固定左端點l,然後移動右端點r,對於該區間[l..r]移動m使該區間消耗代價最低
//當代價不足時,右移左端點,當代價足夠時,右移右端點。每次移動都要求出當前區間的的最低代價
//相當優秀的的做法
//尺取法用到了一個性質就是,隨著右端點右移,帶權中位數點也會右移>=0個單位
//移動m的過程中代價的增加公式需要推導
while(r<=n) { t-=(x[r]-x[m])*a[r]; r++; while
(l<=r) { while(m<r-1) { LL tmp=(s[l-1]+s[r-1]-s[m]*2)*(x[m+1]-x[m]); if(tmp<=0)break; t+=tmp; m++; } if(t>=0) break; t+=a[l]*(x[m]-x[l]); l++; } LL L=0,R=0; if(l>1) L=min(a[l-1],t/(x[m]-x[l-1])); if(r<=n) R=min(a[r],t/(x[r]-x[m])); ans=max(ans,s[r-1]-s[l-1]+max(L,R)); } cout<<ans<<endl; return 0; }