版权声明:本文为博主原创文章,不管你喜不喜欢都请在注明作者后转载~( ̄▽ ̄~) https://blog.csdn.net/C20190102/article/details/82931796
题目
题目大意
给出一个 的排列 ,求 。
思路
题意就是求序列中每个区间的最小值之和。
考虑有多少个区间的最小值为
,记为
,则答案为:
若区间
的最小值为
,则其中的每一个数(除了
)都比
大。
直接说结论:
- 找到 左边离它最近的 ,满足
- 找到 右边离它最近的 ,满足
这样找到的区间
(注意是开的)是满足最小值为
的最大的一个区间。因为区间
的最小值就不是
了,是
(
),同理,区间
的最小值一定是
。
但是在区间
和
中的每个数都比
大,从
中选出一个作为左端点,
中选出一个作为右端点,得到
。
于是你发现,暴力完成这个结论还是 的……
如果我们将比
小的数的下标存在一个set<int> S
里面,那么l=S.lower_bound(i)
(实现的时候用lower_bound
好像会有神奇之事发生,详见代码),r=S.upper_bound(i)
。
所以将
排个序(和下标一块,用结构体),然后顺着扫,将
前面的数都扔到set
里面,再对
的下标(排了序就不是
了)找lower_bound
之类就可以了。
似乎有点像偏序……
反正这个问题我想了几百年……
代码
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200000
int N;
struct node{
int val,ID;
}A[MAXN+5];
bool cmp(node x,node y){
return x.val<y.val;
}
int main(){
scanf("%d",&N);
for(int i=1;i<=N;i++){
A[i].ID=i;
scanf("%d",&A[i].val);
}
sort(A+1,A+N+1,cmp);
set<int> index;
index.insert(0),index.insert(N+1);//免得出现找不到的情况
long long Ans=0;
for(int i=1;i<=N;i++){
set<int>::iterator Left,Right;
Left=Right=index.upper_bound(A[i].ID),Left--;//注意Left的处理
Ans+=1ll*(A[i].ID-*Left)*(*Right-A[i].ID)*A[i].val;
index.insert(A[i].ID);
}
printf("%lld",Ans);
}