题目链接:https://nanti.jisuanke.com/t/41306
解题思路:
一个前提结论就是假定第i个人开始是机洗,那么他前面的肯定都是手洗他后面的都是机洗。这也很好证明,假定我第j个人是手洗,那么j之前的人肯定也都能手洗而不影响结果。
那么就有答案当机洗时间是x时,
很明显对于一个i是取a[i]+y,还是a[i]+(n-i+1)*x,它们的分界点就是y/(n-i+1),然后分段带入线段树中(李超树,后面有时间再专门写一个吧)维护最值
#include
#define mid (l+r>>1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 1e6 + 10;
int n,m,a[mx];
int sk[mx<<2],sb[mx<<2];
int L,R;
void update(int l,int r,int rt,int k,int b)
{
if (L<=l&&r<=R){
int l1 = k*l + b,r1 = k*r + b;
int l2 = sk[rt]*l + sb[rt], r2 = sk[rt]*r + sb[rt];
if (l1<=l2&&r1<=r2) return ;
if (l1>=l2&&r1>=r2) {
sk[rt] = k,sb[rt] = b;
return ;
}
int point = (b-sb[rt]) / (sk[rt]-k);
if (l1>l2){
if (point<=mid) update(lson,k,b);
else {
swap(sk[rt],k);swap(sb[rt],b);
update(rson,k,b);
}
} else {
if (point>=mid) update(rson,k,b);
else {
swap(sk[rt],k);swap(sb[rt],b);
update(lson,k,b);
}
}
} else {
if (L<=mid) update(lson,k,b);
if (R>mid) update(rson,k,b);
}
}
int query(int l,int r,int rt,int x)
{
int ans = sk[rt]*x + sb[rt];
if (l==r) return ans;
if (x<=mid) return max(ans,query(lson,x));
return max(ans,query(rson,x));
}
int main() {
while(~scanf("%d%d",&n,&m)){
int v;
for(int i=1;i<=3*m;i++) sk[i] = sb[i] = 0;
for(int i=1;i<=n;i++) scanf("%d",a+i);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
int pos = m/(n-i+1);
int k = n - i + 1,b = a[i];
L = 1, R = pos;
if(pos) update(1,m,1,k,b);
k = 0, b = a[i]+m;
L = pos+1, R = m;
if(pos!=m) update(1,m,1,k,b);
}
for (int i=1;i<=m;i++)
printf("%d%c",query(1,m,1,i),i==m?'\n':' ');
}
return 0;
}