2019 ICPC 沈阳区域赛 - A Leftbest(set的应用)

题目链接


题目大意

给出一个数组,现在每个数的贡献为该数前面大于该数的最小值,求数组所有数的累积贡献。

解题思路

首先用 s e t set set维护升序,接着二分查找前面第一个比它大的数, s e t set set里自带了 a l g o r i t h m algorithm algorithm里的 l o w e r _ b o u n d lower\_bound lower_bound u p p e r _ b o u n d upper\_bound upper_bound,直接使用 u p p e r _ b o u n d upper\_bound upper_bound查找即可,如果没找到会返回 s e t : : e n d ( ) set::end() set::end()迭代器,判断一下即可

拓展一下这道题,它还能应用于求每个数前面比它大的最大值;每个数前面比它小的最大值;每个数前面比它小的最小值。而本题是每个数前面比它大的最小值。

前缀较大的最小值

复习一下 l o w e r _ b o u n d ( ) lower\_bound() lower_bound() u p p e r _ b o u n d ( ) upper\_bound() upper_bound()

//在set中直接传要查询的元素即可

lower_bound(val);        //查找大于等于val第一个元素的位置,没有找到返回set::end()

upper_bound(val);        //查找大于val第一个元素的位置,没有找到返回set::end()
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
int main(){
    int n,x;
    ll ans=0;
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    set<int> s;
    cin>>n;
    while(n--){
        cin>>x;
        s.insert(x);
        auto i=s.upper_bound(x);
        if(i!=s.end()){
            ans+=*i;
        }
    }
    cout<<ans<<endl;
    return 0;
}
前缀较大的最大值

这里再补充一下几个迭代器分别返回容器的什么位置

begin();     //容器第一个元素的位置

end();       //容器最后一个元素的下一个位置,也就是容器遍历的结束标志,此位置不可访问

rbegin();   //容器逆向的第一个元素,也就是最后一个元素的位置

rend();     //第一个元素的前一个位置
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
int main(){
    int n,x;
    ll ans=0;
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    set<int> s;
    cin>>n;
    cin>>x;
    s.insert(x);
    n--;
    while(n--){
        cin>>x;
        auto it=s.rbegin();  //不能"auto it=s.end()-1;"会报错
        //auto it =s.end(); it--;
        if(x<*it) ans+=*it;
        s.insert(x);
    }
    cout<<ans<<endl;
    return 0;
}
前缀较小的最大值
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
int main(){
    int n,x;
    ll ans=0;
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    set<int> s;
    cin>>n;
    while(n--){
        cin>>x;
        s.insert(x);
        auto it=s.lower_bound(x);
        if(it!=s.begin() && it!=s.end()){  //两边都要考虑,begin是因为可能找不到,end是因为可能都比查找值小
            it--;
            ans+=*it;
        } 
    }
    cout<<ans<<endl;
    return 0;
}
前缀较小的最小值
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
int main(){
    int n,x;
    ll ans=0;
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    set<int> s;
    cin>>n;
    cin>>x;
    s.insert(x);
    n--;
    while(n--){
        cin>>x;
        auto it=s.begin();
        if(x>*it){
            ans+=*it;
        }
        s.insert(x);
    }
    cout<<ans<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值