2019-ICPC沈阳重现(PTA)(STL 二分答案)

在PAT上重现的只是一部分题目。
邀请码:ae17b8c95ce5aac5 链接

A-Leftbest

在这里插入图片描述

只要题意读懂了还是很好写的。题意:遍历每一个元素p,往左边找比p大的元素中最小的元素,找到的话结果就加上这个值,否则不加,最后输出和。很显然每次往左寻找时,排序后二分是最优的复杂度,但是sort的话还是会超时,这里采用更优的set排序,使用成员函数upper_bound()二分查找。

#include<bits/stdc++.h>

using namespace std;

int main()
{
	int n,t;
	scanf("%d",&n);
	long long ans=0;
    set<int> ve;
    set<int> :: iterator it;
	for(int i=1;i<=n;i++){
		scanf("%d",&t);
        if(!ve.empty() ) {
        	it = ve.upper_bound(t);
        	if(it != ve.end() ) ans += *it;
		}
		ve.insert(t); 
	}
	cout<<ans<<endl;
	return 0;
 } 

补充几个STL的用法:
set:

//set的反向迭代器;
set<int> :: reverse_iterator it1 = s.rbegin();
while (it1 != s.rend())
{
     cout << *it1 << " ";
     ++it1;
}

//set的删除;
set<int>::iterator it = se.find(10);
if (it != se.end())   //!=se.end()说明数据存在
{
    se.erase(it);
    //se.erase(it1,it2);  //区间左闭右开 
}

//set的成员函数upper_bound()
if(!se.empty() ) {
  	set<int> :: iterator it = se.upper_bound(10);
  	if(it != se.end() ) cout<< *it;
  }

map:

//map成员函数upper_bound()是按key查找;
map<char,int> :: iterator it, it1, it2;

for(it = mp.begin();it != mp.end(); ++it)
	cout<<it->first<<" "<<it->second<<endl; //输出
it1=mp.lower_bound('b');
it2=mp.upper_bound('d');
mp.erase(it1,it2);  //区间左闭右开

L-Flowers

在这里插入图片描述

听说这题现场赛数据很水。
二分答案:首先最优的情况就是所有的花朵(sum)都用上,则此时最大花束数量为 sum/M,所以以此为右边界,进行二分答案。判定依据:假设此时组成花束数量为 mid,遍历每种花的数量 a[i],若a[i] >= mid 则也只能选mid 朵 ,若a[i] < mid 则全选,累加mid个花束的种情况下花朵的总数量num,与输入的目标 mid * M 朵花比较,若 num >= mid*M 就意味着 mid 需要变大(M不变),即区间右移,反之同理;

#include<bits/stdc++.h>
#define LL long long
using namespace std;

LL N , M, a[300030];

bool check(LL mid){
	LL sum = 0;
	for(int i=0;i<N;i++){
		sum += min(a[i] , mid );  //计算mid个花束时实际有多少多朵花
	}
	return sum >= mid * M;  //与此时的目标花朵数量 mid * M 比较;
} 

int main()
{
	int T;
	cin>>T;
	while(T--){
		LL sum = 0 ;
		scanf("%lld%lld",&N,&M);
		for(int i=0;i<N;i++){
			scanf("%lld",&a[i]);
			sum+=a[i];
		}
		LL l = 0, r = sum/M , mid =0,ans=0;
		while(l<=r){
			mid = l+r>>1;
			if(check(mid)){
				l = mid + 1;
				ans = mid;
			}
			else r = mid - 1;
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值