Leftbest
链接:https://ac.nowcoder.com/acm/contest/7830/A
来源:牛客网
题目描述
Jack is worried about being single for his whole life, so he begins to use a famous dating app. In this app, the user is shown single men/women’s photos one by one, and the user may choose between “yes” and “no”. Choosing “yes” means an invitation while choosing “no” means nothing. The photos would be shown one by one until the number of rest photos to be shown reaches zero. Of course, efficient and single Jack would always choose “yes”.
When viewing photos, Jack would have a “fake impression point” on every photo, which is not accurate. To calculate the “true impression point” of one photo, Jack would recall the “fake impression point” of every previous photo whose “fake impression point” is larger than this photo, and regard the smallest “fake impression point” of them as the “true impression point” of this photo. Jack would like to sum the “true impression point” of all photos as the outcome of his effort.
Note that if such a larger “fake impression point” does not exist, the “true impression point” of this photo is zero.
输入描述:
The first line contains an integer {n}n (1 \le n \le 100,0001≤n≤100000) — the number of photos.
The second line contains n integers is the “fake impression point” of the i-th photo.
输出描述:
Output a single integer — the sum of the “true impression point” of all photos.
示例1
输入
复制
4 2 1 4 3
输出
复制
6
题意:
排在a[i]前面 比a[i]大的数中最小数的和是多少?
题解:
第一反应是用大小堆来做,思路很简单,但是却超时了。。
后来想起来set里面本身就是函数是用来求这个的
lower_bound(val); //查找大于等于val第一个元素的位置,没有找到返回set::end()
upper_bound(val); //查找大于val第一个元素的位置,没有找到返回set::end()
所以直接
j=s.upper_bound(x)就行
STL有好多现成的东西,太久没用都忘得差不多了
代码:
一开始大小堆的代码:
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
const int maxn=1e5+8;
int a[maxn];
typedef long long ll;
priority_queue<int,vector<int>,less<int> >q;//从小到大
priority_queue<int,vector<int>,greater<int> >w;//从大到小
int main()
{
ios::sync_with_stdio(false);
int n;
scanf("%d",&n);
ll sum=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
while(!q.empty())
{
// printf("q.top=%d\n",q.top());
//cout<<"q.top="<<q.top<<endl;
if(q.top()>x)
{
w.push(q.top());
q.pop();
}
else break;
}
if(!w.empty())
sum+=w.top();
while(!w.empty())
{
q.push(w.top());
w.pop();
}
q.push(x);
}
cout<<sum;
return 0;
}
AC代码:
#include<cstdio>
#include<iostream>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1e5+8;
set<int>s;
typedef long long ll;
int main()
{
ios::sync_with_stdio(0);
int n;
cin>>n;
ll sum=0;
while(n--){
int x;
cin>>x;
s.insert(x);
auto j=s.upper_bound(x);
if(j!=s.end())sum+=*j;
}
cout<<sum;
return 0;
}
扩展
刚才那个题求的是前缀较大的最小值
我们扩展到其他几个
注意:
set在内部会自动排序,且会自动查重(即每个数最多出现一次)
前缀较大的最大值
#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;
}