Loading

zhy's sol of P8518 [IOI2021] 分糖果

orz zhouhuanyi

zhouhuanyi 给出了一个 “拆电路” 的做法,利用了这个公式:\(\min(\max(x,y),z)=\max(\min(x,z),\min(y,z))\)。这可以直接把答案表示成一个 \(\min\)\(\max\) 的式子。下面是具体做法。

我们可以扫描线维护每一个盒子的操作序列。所以接下来只分析一个盒子,将其容量固定为 \(c\)

\(f(x,v)\) 表示一个盒子原来有 \(x\) 块糖,进行 \(v\) 操作后的糖果数量。容易得到:

\[f(x,v)=\max(\min(c,x+v),0)=\min(\max(0,x+v),c) \]

我们可以归纳地证明,每个结果都可以表示为 \(x=p+\min_{T\in S}\max T\) 的形式。

\[\begin{aligned} f(x,v-p)=&\max(\min(c,x+v-p),0)\\ =&\max(\min(c-v,\min_{T\in S}\max T)+v,0)\\ =&\max(-v,\min_{T\in S\cup\{c-v\}}\max T)+v\\ =&v+\min\max_{T\in S\cup\{c-v\}}T\cup\{-v\} \end{aligned} \]

将归纳过程展开,我们可以得到结论:对于一个数,设操作序列为 \([p_1,p_2,\cdots,p_q]\),将其前缀和得 \([s_1,s_2,\cdots,s_q]\)。最终结果为

\[s_q+\min_{i=0}^q\max_{j=i}^q\{c-s_j,-s_{j+1},\cdots,-s_q\} \]

由于 \(0=0+\min\max\{c-c\}\)\(s_0\) 应当为 \(c\)

\(b_i=-s_i,A(i)=\max_{j=i}^q\{c+b_j,b_{j+1},\cdots,b_q\}\)

每次插入一个操作 \(i\) 时,\(b\) 的一个后缀会减去 \(v_i\);删除一个操作 \(i\) 时,\(b\) 的一个后缀会加上 \(v_i\)

现在我们只要求最小的 \(A(i)\)。可以发现,如果 \(i<j,b_i>b_j\),则一定有 \(A(i)>A(j)\)。那么,最优的位置 \(x\) 一定满足 \(b_x=\min\{b_x,b_{x+1},\cdots,b_q\}\),合法的位置构成了上升子序列的结构。最终 \(A(x)\) 的值是后缀最大值和 \(c+b_x\) 中较大的那个,而前者递减,后者递增,\(A(x)\) 的图像是两边高中间低的,分界点就是后缀最大值与 \(c+b_x\) 大小关系第一次改变的地方,这可以二分得到。

于是用线段树维护区间最大值和最小值,二分最后一个后缀最小值加 \(c\) 不大于后缀最大值的点,取这个点和下一个点的答案的最小值即可,时间复杂度为 \(O(n+q\log^2q)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int>vi;
constexpr int N=2e5+5;
ll miv[N<<2],mxv[N<<2],tag[N<<2];vi ins[N],del[N];
void pushdown(int p){
	miv[p<<1]+=tag[p];mxv[p<<1]+=tag[p];tag[p<<1]+=tag[p];
	miv[p<<1|1]+=tag[p];mxv[p<<1|1]+=tag[p];tag[p<<1|1]+=tag[p];
	tag[p]=0;
};
void pushup(int p){
	miv[p]=min(miv[p<<1],miv[p<<1|1]);mxv[p]=max(mxv[p<<1],mxv[p<<1|1]);
}
void upd(int p,int l,int r,int L,int R,ll x){
	if(L<=l&&r<=R)return miv[p]+=x,mxv[p]+=x,tag[p]+=x,void();
	int mid=(l+r)>>1;pushdown(p);
	if(L<=mid)upd(p<<1,l,mid,L,R,x);
	if(R>mid)upd(p<<1|1,mid+1,r,L,R,x);
	pushup(p);
};
ll askmx(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return mxv[p];
	int mid=(l+r)>>1;pushdown(p);
	if(R<=mid)return askmx(p<<1,l,mid,L,R);
	if(L>mid)return askmx(p<<1|1,mid+1,r,L,R);
	return max(askmx(p<<1,l,mid,L,R),askmx(p<<1|1,mid+1,r,L,R));
};
ll askmi(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R)return miv[p];
	int mid=(l+r)>>1;pushdown(p);
	if(R<=mid)return askmi(p<<1,l,mid,L,R);
	if(L>mid)return askmi(p<<1|1,mid+1,r,L,R);
	return min(askmi(p<<1,l,mid,L,R),askmi(p<<1|1,mid+1,r,L,R));
};
vi distribute_candies(vi c,vi l,vi r,vi v){
	int q=v.size(),n=c.size();ll S=0;
	for(int i=0;i<q;i++)ins[l[i]].push_back(i),del[r[i]].push_back(i);
	vi ans(n);for(int i=0;i<n;i++){
		for(int j:ins[i])upd(1,1,q,j+1,q,-v[j]),S+=v[j];
		int x=0;ans[i]=min((ll)c[i],max(0ll,askmx(1,1,q,1,q))+S);
		for(int k=17;~k;k--){
			if(x+(1<<k)<=q&&askmi(1,1,q,x+(1<<k),q)+c[i]<=askmx(1,1,q,x+(1<<k),q))x+=1<<k;
		}
		if(x)ans[i]=min((ll)ans[i],askmx(1,1,q,x,q)+S);
		if(x<q)ans[i]=min((ll)ans[i],askmi(1,1,q,x+1,q)+c[i]+S);
		for(int j:del[i])upd(1,1,q,j+1,q,v[j]),S-=v[j];
	}
	return ans;
}
posted @ 2023-03-15 18:39  hihihi198  阅读(57)  评论(0)    收藏  举报