题解:P11261 [COTS 2018] 直方图 Histogram
来一发线性做法。
首先考虑枚举区间如何计算这个区间的答案,可以发现对于区间
考虑枚举
考虑每个位置
我们现在确定了
考虑怎么统计所有长度大于等于
下面不妨记左端点可取值有
注意上方对区间计算和式时下界需要和
运算过程中可能会爆 long long,但答案不会爆。所以 unsigned long long 自然溢出即可。
时间复杂度为
代码里面我写成了笛卡尔树。实际上是不用的。
int n;
ll p;
int h[N];
int minn[N][17],idx[N][17];
int tot;
int ls[N],rs[N];
int L[N],R[N];
ull val[N];
int cut[N];
int rt;
pii merge(pii x,pii y){
if(x.fi==y.fi) return mp(x.fi,min(x.se,y.se));
return min(x,y);
}
pii query(int l,int r){
int len=__lg(r-l+1);
return merge(mp(minn[l][len],idx[l][len]),mp(minn[r-(1<<len)+1][len],idx[r-(1<<len)+1][len]));
}
void build(int &x,int l,int r){
tot++,x=tot;
L[tot]=l,R[tot]=r;
if(l>r) return void();
tie(val[x],cut[x])=query(l,r);
build(ls[x],l,cut[x]-1);
build(rs[x],cut[x]+1,r);
}
ull pres[N];
ull press[N];
ull ans;
ull sum(int l,int r){
return 1ull*(l+r)*(r-l+1)/2;
}
void calc(int x){
if(L[x]>R[x]) return;
ull lim=(p+val[x]-1)/val[x];
int lef=cut[x]-L[x]+1;
int rig=R[x]-cut[x]+1;
{
ull le=max(lim,1ull),re=min(lef,rig);
if(le<=re){
ans-=pres[re]-pres[le-1];
ans+=sum(le,re)*(val[x]+1);
}
}
{
ull le=max(lim,min(lef,rig)+1ull),re=max(lef,rig);
if(le<=re){
ull coef=min(lef,rig);
ans-=coef*(press[re]-press[le-1]);
ans+=coef*(re-le+1)*(val[x]+1);
}
}
{
ull le=max(lim,max(lef,rig)+1ull),re=R[x]-L[x]+1;
if(le<=re){
ans-=(re+1)*(press[re]-press[le-1]);
ans-=sum(le,re)*(val[x]+1);
ans+=(re+1)*(re-le+1)*(val[x]+1);
ans+=pres[re]-pres[le-1];
}
}
calc(ls[x]);
calc(rs[x]);
}
// #define Shun cute
int main(){
#ifdef Shun
freopen(".in","r",stdin);
// freopen(".out","w",stdout);
#endif
ios::sync_with_stdio(false);
cin>>n>>p;
fr1(i,1,n) pres[i]=pres[i-1]+1ull*i*((p+i-1)/i);
fr1(i,1,n) press[i]=press[i-1]+1ull*(p+i-1)/i;
fr1(i,1,n) cin>>h[i];
fr1(i,1,n) minn[i][0]=h[i],idx[i][0]=i;
fr1(j,1,16){
fr1(i,1,n-(1<<j-1)){
tie(minn[i][j],idx[i][j])=merge(mp(minn[i][j-1],idx[i][j-1]),mp(minn[i+(1<<j-1)][j-1],idx[i+(1<<j-1)][j-1]));
}
}
build(rt,1,n);
calc(rt);
cout<<ans<<'\n';
ET;
}