首先来叙述下我的弱小,把这道题看完之后,第一个反应是——水题。。。然后蒟蒻脑子就是一片空白。。。。。
MD,连水题都不会做,我太菜了,那么先上题https://ac.nowcoder.com/acm/contest/984/A
题目大意:给你一排数列,求从每一位开始一直到比大于等于它的那一位数结束,其中有a[i]位,求所有a[i]之和。
例如:给你一个数列 10 3 7 4 12 2
从10开始一直到12,中间有3个数,即a[1]=3
从3开始一直到7,中间有0个数,即a[2]=0
从7开始一直到12,中间有1个数,即a[3]=1
从4开始一直到12,中间有0个数,即a[4]=0
从12开始一直到末尾,中间有1个数,即a[5]=1
从2开始一直到末尾,中间有0个数,即a[6]=0
那么加起来的总和即为3+1+1=5
当我看到这道题的时候,心里就想,不就是个数列嘛,有什么难的,结果一开始想的思路就不对,卡了1个多小时,多亏了左学长的指点,我才写完(我不会告诉你我在后面的二分上又卡了一个多小时的)
思路:用单调栈,每一次判断是否比栈顶上的元素大,如果大的话,需要将其压入到比需要压入的数大的栈内元素上去
以上面这个数列为例:
第一次,栈内无元素,将10压入;
第二次,栈顶元素为10,3比10小,3压入到10的上面,此时3的贡献值为1
第三次,栈顶元素为3,7比3大,但是7比10小,故将3以上的元素弹出,将7压入到10上面,此时7的贡献值为1
第四次,栈顶元素为7,4比7小,4压入到7上面,此时4的贡献值为2
第五次,栈顶元素为4,12比4大,同时比10大,所以将10以上的元素弹出,将12压入,此时12的贡献值为0
第六次,栈顶元素为12,2比12小,将2压入,此时2的贡献值为1;
求出所有贡献值之和5,即为答案
在每一次压入操作中,我们需要用二分查找来找到每一个数需要压入的位置,然后进行操作,由于本人太菜,在写二分的时候经常搞不懂边界,导致经常出错。。然后这题又卡了一个小时,无颜以对。。。。(为了避免找不到边界的问题,可以试着用用STL— lower_bound()这类函数)
嘛不说了上代码:
#include <bits/stdc++.h>
const int maxn=8e4+7;
using namespace std;
int hi[maxn],n;
int tack[maxn],op=0;
void sech(int x){
if(op==0){
op++;
}
else{
int r=op,l=1,mid;
while(r-l){
mid=(l+r)>>1;
if(tack[mid]>hi[x])
l=mid+1;
else
r=mid;
}//二分需要处理好边界问题
op=l;
if(tack[l]>hi[x])
op++;
//因为每一次比较可能原来栈的大小不会改变,而又需要加入一个新元素鼓此处op++
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&hi[i]);
}
long long ans=0;
for(int i=1;i<=n;i++){
sech(i);
ans+=(op-1);
tack[op]=hi[i];
}
printf("%lld",ans);
return 0;
}