title
Description
小x 在学习数列。他想到一个数学问题: 现在有 \(N\) 个数的数列。现在你定义一个子序列是数列的连续一部分,子序列的值是这个子序列中最大值和最小值之差。 给你这 \(N\) 个数,小x 想知道所有子序列的值得累加和是多少。
Input Format
第一行一个整数 \(N(2\leqslant N\leqslant 3e5)\) 接下来 \(N\) 行,每行一个整数 \(A_i(0<A_i\leqslant 1e8)\),表示数列的值。
Output Format
一个整数,所求的子序列值得累加和。
analysis
这题还真是一个答案计数题。
我们只需要搞清楚每个子区间的最值之差即可,但是复杂度不允许,我们需要用数据结构来维护一下。
我们规定:\(Max[i]\) 表示第 \(i\) 个数值是多少区间的最大值,\(Min[i]\) 表示第 \(i\) 个数值是多少区间的最小值。
那么答案就是 \(\sum Max[i]*a[i]-\sum Min[i]*a[i]\)。
不过怎样得到 \(Max[i]\) 和 \(Min[i]\) 呢?
我们只需要用四个单调栈来维护,分别找到这个数向左有多少个区间是最值,向右有多少个区间是最值就好了。
最后用上述公式统计即可。
code
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=3e5+10;
typedef ll larr[maxn];
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getc();
while (!isdigit(ch) && ch^'-') ch=getc();
if (ch=='-') f=-1, ch=getc();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getc();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
ll top1,top2,top3,top4,ans;
larr s1,s2,s3,s4,a;
larr sum1,sum2,sum3,sum4;
int main()
{
ll n;read(n);
for (ll i=1; i<=n; ++i) read(a[i]);
s1[++top1]=1, s2[++top2]=n;
s3[++top3]=1, s4[++top4]=n;
for (ll i=2; i<=n; ++i)//正序 最小
{
while (a[i]<a[s1[top1]] && top1) sum1[i]+=sum1[s1[top1]]+1, --top1;
s1[++top1]=i;
}
for (ll i=n-1; i>=1; --i)//逆叙 最小
{
while (a[i]<=a[s2[top2]] && top2) sum2[i]+=sum2[s2[top2]]+1, --top2;
s2[++top2]=i;
}
for (ll i=2; i<=n; ++i)//正序 最大
{
while (a[i]>a[s3[top3]] && top3) sum3[i]+=sum3[s3[top3]]+1, --top3;
s3[++top3]=i;
}
for (ll i=n-1; i>=1; --i)//逆序 最大
{
while (a[i]>=a[s4[top4]] && top4) sum4[i]+=sum4[s4[top4]]+1, --top4;
s4[++top4]=i;
}
for (ll i=1; i<=n; ++i) ans+=((sum3[i]+1)*(sum4[i]+1)-(sum1[i]+1)*(sum2[i]+1))*a[i];
write(ans,'\n');
IO::flush();
return 0;
}