luogu P2422 良好的感觉 单调栈
题目描述
kkk做了一个人体感觉分析器。每一天,人都有一个感受值Ai,Ai越大,表示人感觉越舒适。在一段时间[i, j]内,人的舒适程度定义为[i, j]中最不舒服的那一天的感受值 * [i, j]中每一天感受值的和。现在给出kkk在连续N天中的感受值,请问,在哪一段时间,kkk感觉最舒适?
输入输出格式
输入格式:
第一行为N,代表数据记录的天数
第二行N个整数,代表每一天的感受值
输出格式:
一行,表示在最舒适的一段时间中的感受值。
题解:
看上去无从下手,不妨枚举那个最不舒服的感受值(即一段区间中最小值).
令 $f_{i}$ 表示 $i$ 位置为最小值所能扩展的最大区间的感受值之和.
用一个单调递增的队列维护最小感受值.
考虑新加入一个元素 $a_{i}$.
如果当前队首大于 $a_{i}$,那么 $i$ 就是队首能扩展到的最大位置了,弹出队首,把队首的 $f_{j}$ 值加上 $sum(i-1)-sum(j)$,一直反复弹栈操作.
最后,将 $a_{i}$ 推进.
因为栈时单调递增的,$a_{i}$ 再栈中前一个元素肯定小于等于 $a_{i}$,所以当前的贡献就是 $f_{i}=sum(i)-sum(q_{top})$.
但是.....1. 多个元素大小相等怎么办 ? 2. 到最后都弹不掉怎么办 ?
在最后加入一个 0,即可解决上述问题.
令 $f_{i}$ 表示 $i$ 位置为最小值所能扩展的最大区间的感受值之和.
用一个单调递增的队列维护最小感受值.
考虑新加入一个元素 $a_{i}$.
如果当前队首大于 $a_{i}$,那么 $i$ 就是队首能扩展到的最大位置了,弹出队首,把队首的 $f_{j}$ 值加上 $sum(i-1)-sum(j)$,一直反复弹栈操作.
最后,将 $a_{i}$ 推进.
因为栈时单调递增的,$a_{i}$ 再栈中前一个元素肯定小于等于 $a_{i}$,所以当前的贡献就是 $f_{i}=sum(i)-sum(q_{top})$.
但是.....1. 多个元素大小相等怎么办 ? 2. 到最后都弹不掉怎么办 ?
在最后加入一个 0,即可解决上述问题.
#include<bits/stdc++.h>
#define maxn 1000000
#define ll long long
using namespace std;
void setIO(string s)
{
string in=s+".in";
freopen(in.c_str(),"r",stdin);
}
int S[maxn],top,n;
ll f[maxn],sumv[maxn],arr[maxn];
int main()
{
// setIO("input");
S[++top]=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%lld",&arr[i]);
sumv[i]=sumv[i-1]+arr[i];
while(arr[S[top]] > arr[i])
{
f[S[top]] += sumv[i-1]-sumv[S[top]];
--top;
}
f[i]=sumv[i]-sumv[S[top]];
S[++top]=i;
}
ll ans=0;
for(int i=1;i<=n;++i) ans=max(ans,f[i]*arr[i]);
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号