在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;
}