本文网址:https://www.cnblogs.com/zsc985246/p/16621286.html ,转载请注明出处。
题目大意
给定一个 n 个数的序列 a,求
n∑i=1n∑j=i(j−i+1)min(ai,ai+1,…,aj)max(ai,ai+1,…,aj)
即:求序列 a 的所有子序列的 最小值×最大值×序列长度 的和。
思路
考虑分治。
那么问题转化为:计算区间左端点在 [l,mid],右端点在 (mid,r] 时对答案的贡献。
令区间左端点为 i,区间 [i,mid] 中最大值为 maxx,最小值为 minn;
p 为满足 minn<min(amid+1,amid+2,…,aq) 的最大 p;
q 为满足 maxx>max(amid+1,amid+2,…,ap) 的最大 q;
w1=min(p,q),w2=max(p,q)。
则对于 (mid,r] 这段区间,可以分为三个小区间:
-
(mid,w1]:所有子序列的最大最小值均为定值;
-
(w1,w2]:所有子序列的最大最小值有一个为定值;
-
(w2,r]:所有子序列的最大最小值均不为定值。
第一个区间对答案的贡献为:
w1∑j=mid+1(j−i+1)min(ai,ai+1,…,aj)max(ai,ai+1,…,aj)=w1∑j=mid+1(j−i+1)×minn×maxx =minn×maxx×w1∑j=mid+1(j−i+1) =minn×maxx×((mid+1−i+1)+(w1−i+1))×(w1−(mid+1)+1)2=minn×maxx×(w1+mid−2×i+3)×(w1−mid)2
第二个区间对答案的贡献分两种情况:
- p>q
那么 minn 是定值,贡献为:
q∑j=mid+1(j−i+1)min(ai,ai+1,…,aj)max(ai,ai+1,…,aj)=q∑j=mid+1(j−i+1)×minn×max(ai,ai+1,…,aj) =minn×q∑j=mid+1(j−i+1)×max(ai,ai+1,…,aj)
对于后面的求和,实际上是可以前缀和优化的。只需要将求和中的 i 拆分出来。
=minn×q∑j=mid+1(j−i+1)×max(amid+1,amid+2,…,aj) =minn×q∑j=mid+1(j−mid+mid−i+1)×max(amid+1,amid+2,…,aj)=minn×(q∑j=mid+1(mid−i+1)×max(amid+1,amid+2,…,aj)+q∑j=mid+1(j−mid)×max(amid+1,amid+2,…,aj))
化简到这里,我们发现已经可以前缀和优化了。
s1mid=0
s1x(x∈(mid,r])=s1x−1+((x−mid)×max(amid+1,amid+2,⋯,ax)
s1′mid=0
s1′x(x∈(mid,r])=s1′x−1+max(amid+1,amid+2,⋯,ax)
所以原式化为:
minn×((mid−i+1)×(s1′p−s1′q)+(s1p−s1q))
- p<q
同 1 可得:
s2mid=0
s2x(x∈(mid,r])=s2x−1+((x−mid)×min(amid+1,amid+2,⋯,ax)
s2′mid=0
s2′x(x∈(mid,r])=s2′x−1+min(amid+1,amid+2,⋯,ax)
对答案的贡献为:
maxx×((mid−i+1)×(s2′q−s2′p)+(s2q−s2p))
第三个区间对答案的贡献计算与第二个区间的思路大体相同:
s3mid=0
s3x(x∈(mid,r])=s3x−1+((x−mid)×min(amid+1,amid+2,⋯,ax)×max(amid+1,amid+2,⋯,ax)
s3′mid=0s3′x(x∈(mid,r])=s3′x−1+min(amid+1,amid+2,⋯,ax×max(amid+1,amid+2,⋯,ax))
对答案的贡献为:
(mid−i+1)×(s3′r−s3′w2)+(s3r−s3w2)
最后综合一下即是答案。
代码实现
#include<bits/stdc++.h>
#define ll long long
const ll N=500010;
const ll mod=1e9;
using namespace std;
ll n,a[N],s1[N],s1_[N],s2[N],s2_[N],s3[N],s3_[N];
ll ans;
void f(ll l,ll r){
if(l==r){
ans=(ans+a[l]*a[l]%mod+mod)%mod;
return;
}
ll mid=l+r>>1;
ll minn=a[mid+1],maxx=a[mid+1];
s2[mid]=s1[mid]=s3[mid]=s2_[mid]=s1_[mid]=s3_[mid]=0;
for(ll i=mid+1;i<=r;++i){
minn=min(minn,a[i]),maxx=max(maxx,a[i]);
s1[i]=(s1[i-1]+maxx*(i-mid)%mod+mod)%mod;
s1_[i]=(s1_[i-1]+maxx+mod)%mod;
s2[i]=(s2[i-1]+minn*(i-mid)%mod+mod)%mod;
s2_[i]=(s2_[i-1]+minn+mod)%mod;
s3[i]=(s3[i-1]+minn*maxx%mod*(i-mid)%mod+mod)%mod;
s3_[i]=(s3_[i-1]+minn*maxx%mod+mod)%mod;
}
ll i,p,q;
i=p=q=mid;
minn=maxx=a[mid];
while(i>=l){
minn=min(minn,a[i]),maxx=max(maxx,a[i]);
while(p<r&&a[p+1]>minn)++p;
while(q<r&&a[q+1]<maxx)++q;
ll w1=min(p,q),w2=max(p,q);
if(w1>mid)ans=(ans+minn*maxx%mod*((mid-2*i+w1+3)*(w1-mid)/2%mod)%mod+mod)%mod;
if(p>q){
ans+=(minn*((mid-i+1)*(s1_[p]-s1_[q]+mod)%mod+(s1[p]-s1[q]+mod)%mod)%mod+mod)%mod;
}
if(p<q){
ans+=(maxx*((mid-i+1)*(s2_[q]-s2_[p]+mod)%mod+(s2[q]-s2[p]+mod)%mod)%mod+mod)%mod;
}
ans+=(((mid-i+1)*(s3_[r]-s3_[w2]+mod)%mod+(s3[r]-s3[w2]+mod)%mod)%mod+mod)%mod;
i--;
}
f(l,mid);
f(mid+1,r);
}
int main(){
scanf("%lld",&n);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
f(1,n);
printf("%lld\n",ans%mod);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现