zhy's sol of P8518 [IOI2021] 分糖果
orz zhouhuanyi
zhouhuanyi 给出了一个 “拆电路” 的做法,利用了这个公式:。这可以直接把答案表示成一个 套 的式子。下面是具体做法。
我们可以扫描线维护每一个盒子的操作序列。所以接下来只分析一个盒子,将其容量固定为 。
设 表示一个盒子原来有 块糖,进行 操作后的糖果数量。容易得到:
我们可以归纳地证明,每个结果都可以表示为 的形式。
将归纳过程展开,我们可以得到结论:对于一个数,设操作序列为 ,将其前缀和得 。最终结果为
由于 , 应当为 。
设 。
每次插入一个操作 时, 的一个后缀会减去 ;删除一个操作 时, 的一个后缀会加上 。
现在我们只要求最小的 。可以发现,如果 ,则一定有 。那么,最优的位置 一定满足 ,合法的位置构成了上升子序列的结构。最终 的值是后缀最大值和 中较大的那个,而前者递减,后者递增, 的图像是两边高中间低的,分界点就是后缀最大值与 大小关系第一次改变的地方,这可以二分得到。
于是用线段树维护区间最大值和最小值,二分最后一个后缀最小值加 不大于后缀最大值的点,取这个点和下一个点的答案的最小值即可,时间复杂度为 。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现