题目链接
https://ac.nowcoder.com/acm/contest/7604/D
解题思路
参考
先看看大佬的大致思路,再看我的代码讲解。
代码讲解
先扫一眼代码,再看讲解。
构建最大值/最小值区间:
大佬写的代码比较难理解,但是时间复杂度应该比这样低点。
抽丝剥茧,分离出本质,就是找第i个位置之后第一个比a[i]大的位置,将其保存在ka[i]中。
所以说,区间[i,ka[i]-1]的最大值为a[i]。
同理,找到第i个位置之后第一个比a[i]小的位置,将其保存在ki[i]中。区间[i,ki[i]-1]的最小值为a[i]。
接下来的循环
ans[i]表示区间长度为i的最终和与区间长度为i-1的最终和之差。
枚举起点位置,找到最大值最小值都不变的一段区间,让ans[L]+=最大值最小值,ans[R+1]-=最大值最小值。
每一段区间的更新,右端点都是用最大值右端点和最小值右端点最小的去更新。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
int a[N],ki[N],ka[N],ans[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
//构建最大值区间
for(int i=n;i>=1;i--) {
int j=i+1;
for(;j<=n;j++)
if(a[j]>a[i]) {ka[i]=j;break;}
if(j==n+1) ka[i]=n+1;
}
//构建最小值区间
for(int i=n;i>=1;i--) {
int j=i+1;
for(;j<=n;j++)
if(a[j]<a[i]) {ki[i]=j;break;}
if(j==n+1) ki[i]=n+1;
}
for(int i=1;i<=n;i++) {
int ma=i;//区间最大值的位置
int mi=i;//区间最小值的位置
int minL=i;//最小值区间的左端点
int minR=ki[minL]-1;//最小值区间的右端点
int maxL=i;//最大值区间的左端点
int maxR=ka[maxL]-1;//最大值区间的右端点
while(1) {
int L=minL-i+1,R=min(minR,maxR)-i+1;
//差分数组赋值
ans[L] +=a[mi]*a[ma];
ans[R+1]-=a[mi]*a[ma];
//刷新最大值区间左端点和最小值区间左端点
minL=maxL=min(minR,maxR)+1;
if(minL>=n+1) break;
//刷新最大值区间右端点和最小值区间右端点
if(minL>minR) mi=minL,minR=ki[minL]-1;
if(maxL>maxR) ma=maxL,maxR=ka[maxL]-1;
}
}
for (int i=1;i<=n;i++) ans[i]+=ans[i-1];//差分求和
for (int i=1;i<=n;i++) cout<<ans[i]<<' ';
}吐槽
太难了吧

京公网安备 11010502036488号