HNOI2016 序列 题解
HNOI2016 序列 题解
我做离线版本时往了偏序方向想,但是发现非常麻烦。直到看到了在线版本的容斥做法,发现既好写又跑得快。
首先考虑容斥,我们不妨把一个询问
- 子区间跨过
,贡献即 。 - 子区间在
左侧。 - 子区间在
右侧。
对于子区间在
以下我们记
那么
在这里我们运用了
设
怎么求
考虑把最小值为
我们再来看
那么这道题就做完了,瓶颈在于 RMQ,可以使用 ST 表做到
代码难度较低,细节不多。
AC 代码:
using gen::init; using gen::input; using gen::output; using gen::finish; const int N=1e5+5; int a[N]; pair<int,int> mn[17][N]; int get(int l,int r){ int len=r-l+1; return min(mn[__lg(len)][l],mn[__lg(len)][r-(1<<__lg(len))+1]).second; } int stk[N],top=0; int L[N],R[N]; ll f[N],F[N],g[N],G[N]; signed main(){ read(n,Q,type); fo(i,1,n){ read(a[i]); mn[0][i]={a[i],i}; while(top&&a[stk[top]]>=a[i])--top; L[i]=stk[top]; stk[++top]=i; F[i]=F[L[i]]+(ll)(i-L[i])*a[i]; f[i]=f[i-1]+F[i]; } stk[top=0]=n+1; fd(i,n,1){ while(top&&a[stk[top]]>=a[i])--top; R[i]=stk[top]; stk[++top]=i; G[i]=G[R[i]]+(ll)(R[i]-i)*a[i]; g[i]=g[i+1]+G[i]; } fo(i,1,__lg(n)){ fo(j,1,n-(1<<i)+1){ mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<i-1)]); } } if(type==1)init(); while(Q--){ int l,r; if(type==1)input(l,r); else read(l,r); ull ans=0; int pos=get(l,r); ans=(ull)a[pos]*(pos-l+1)*(r-pos+1); ans+=g[l]-g[pos]-(ll)G[pos]*(pos-l)+f[r]-f[pos]-F[pos]*(r-pos); output(ans); } finish(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通