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

orz zhouhuanyi

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

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

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

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

我们可以归纳地证明,每个结果都可以表示为 x=p+minTSmaxT 的形式。

f(x,vp)=max(min(c,x+vp),0)=max(min(cv,minTSmaxT)+v,0)=max(v,minTS{cv}maxT)+v=v+minmaxTS{cv}T{v}

将归纳过程展开,我们可以得到结论:对于一个数,设操作序列为 [p1,p2,,pq],将其前缀和得 [s1,s2,,sq]。最终结果为

sq+mini=0qmaxj=iq{csj,sj+1,,sq}

由于 0=0+minmax{cc}s0 应当为 c

bi=si,A(i)=maxj=iq{c+bj,bj+1,,bq}

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

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

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

#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 @   hihihi198  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩