本贴主要针对 yuanruiqi 大佬的 O(n) 题解做自己的个人理解,可能能解决你的一些疑惑。
首先是关于 特殊性质A 的 说明,特殊性质A保证只有一个正数。
令 cp>0, Ri 是第一个满足 aj>ai 且大于 i 的 j 值。
则我们如果 想要拿到 cp 的正贡献,必然有某个区间为 [p,pr](pr≥Rp) 。 且由于后面全部都是负数,所以不需要取后面,剩下一直区间不动就好了。即区间为 [p,Rp]
在 p 前面的部分,我们又应该尽可能少取,所以我们每次尽可能让数字从左端离开,这时不会记录 sum , 所以理想的区间长度每次均为 1。由此可以简单得到 8 分代码
这里解释一下题解中的 这个过程启发我们关注队列中只有一个元素的时刻 这句话。
因为有 n 个区间, 所以 ri 可以一个一个地覆盖到 n ,而且多余的区间可以以重复区间给冲掉,因此实际上可以视为不超过 n 个区间。
又因为我们从左端退栈不需要计算 sum ,所以我们可以设计让多余元素 ai 从左端退栈 (前提是他不会被 ai+1 弹掉。)这样就不会引起其他变化。
这个时候,当我们固定 rn , 我们可以通过构造,使得 ln=rn 或者 Rln=rn , 使得当取到最后的时候,队列中只剩下 rn , 而不引起其他变化。
所以,用 fi 来记录栈中只剩下 ci 一个元素从而计算 min{fi} 作为答案是可行的。
而让 ai 计算贡献的方法,一定是他被通过某一个方式弹掉了,这个时候,必然存在某个 rj>Ri 。且那个时候,因为 aRi 是第一个大于 ai 的,所以当栈中只有 ai 时,转移出的 fRi 也一定只含有 aRi
第29行有一句
f[i + 1] = max(f[i + 1], f[i] + (a[i + 1] > a[i] ? c[i] : 0));
实际上,a[i]<a[i+1] 不需要判断,因为这种情况已经包括在下面的 fpi 计算之下了。实测修改代码为以下代码也可AC
if (a[i]>a[i+1]) f[i+1] = f[i];
感觉这实际上是一种理解的问题,大佬的做法是对 "大于和小于" 的分类讨论,而后者更像是对 a[i]<a[i+1] 的特判。
// 以下代码在 #define F(i,l,r) for(int i=l; i<=r; i++) 下运行
int n;
int a[LXB];
int c[LXB];
void solve()
{
// 仅有一个正数
cin>>n;
F(i,1,n) cin>>c[i];
F(i,1,n) cin>>a[i];
int x=0;
F(i,1,n){
if (a[i]>a[i-1]) x+=c[i-1];
if (c[i]>0){
F(j,i+1,n){
x+=c[j-1];
if (a[j]>a[i]){
cout<<max(0ll,y)<<endl;
return ;
}
}
cout<<0<<endl;
return ;
}
}
}