题解:P11805 [PA 2017] 烧饼 2
OIer_Automation · · 题解
首先不难发现,一定有一种最优方案,使得这些人拿到烧饼的顺序就是他们来到店里的顺序。证明考虑调整,若交换顺序,要么后者无法购买前者的烧饼,要么一个人的等待时间增加
考虑设第
因为前者是来店时间,后者是下一块烧饼做好的时间,当前时间要同时不小于两者,取最大值最优。此时答案即为
考虑到
这个最大值的形式让人恼火,因为它较为难求,不妨考虑分类讨论,即讨论什么时候
证明是容易的,因为此时不管从什么时候开始连续制作烧饼,都无法让第
于是可以采用凸包维护,于是第
那么此时对于一个
注意到因为
现在考虑如何对
code
#include <bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#define pil pair<int,ll>
#define fi first
#define se second
const int N=2e5+5;
int n,m,q,top;
int id[N],rk[N],d[N];
ll s1,s2;
ll t[N],_d[N],pos[N],ans[N];
pil stk[N];
struct Node{
int pre,nxt;
}l[N];
pil operator -(pil _1,pil _2){return {_1.fi-_2.fi,_1.se-_2.se};}
ll operator *(pil _1,pil _2){return _1.fi*_2.se-_1.se*_2.fi;}
il void Insert(int i){
pil p={i,t[i]};
while(top&&(p-stk[top])*(p-stk[top-1])<=0)top--;
pos[i]=upper_bound(_d+1,_d+1+m,(t[i]-stk[top].se)/(i-stk[top].fi))-_d,stk[++top]=p;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>t[i],rk[i]=i,l[i]={i-1,i+1};
for(int i=1;i<=m;i++)cin>>d[i],_d[i]=d[i],id[i]=i;
sort(_d+1,_d+1+m);
for(int i=1;i<=n;i++)Insert(i);
sort(id+1,id+1+m,[](int _1,int _2){return d[_1]<d[_2];}),sort(rk+1,rk+1+n,[](int _1,int _2){return pos[_1]<pos[_2];});
for(int i=1,p=1;i<=m;i++){
while(p<=n&&pos[rk[p]]==i){
int now=rk[p++],pre=l[now].pre,nxt=l[now].nxt;
s1+=(nxt-now)*(t[pre]-t[now]),s2+=(ll)(nxt-now)*(now-pre),l[pre].nxt=nxt,l[nxt].pre=pre;
}
int idx=id[i];
ans[idx]=s1+s2*d[idx];
}
for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
}