题目:
http://codevs.cn/problem/2382/
这道题很难;
思路:
设a挂缀承受能力为ca,重量为wa,
b挂缀承受能力为cb,重量为wb,
设x为a,b下面的挂缀总重量;
若a在b上面更好(剩余承受能力更多),即:a.c-b.w-x > b.c-a.w-x;
移项得 a.c+a.w > b.c+b.w;
令d=(承受能力+重量)
所以,我们需要对每种挂缀的d进行排序;
然后,我们发现这仅仅只是一个贪心的方向;
若a.d>b.d,则a未必在b上面,因为a的承受能力可能比b小;
结合题目要求,最终输出最小重量;
有没有DP的感觉?
但是,这显然不是DP,因为数据范围太大,显然是小于O(nlogn)的做法;
所以,还要考无敌的贪心;
维护一个堆,像http://blog.csdn.net/qq_36312502/article/details/78249623那样做就可以了;
注意我们由小及大,所以考虑从下往上组成这个挂缀,这样就可以由大的更新小的了;
题外话:
这题我连WA五遍,然后改了半个小时;
最后发现没有将调试时写的代码去干净,QAQ!
堆的基本操作为O(logn),最多执行n次,排序为O(nlogn),
所以总复杂度为O(nlogn);
总结:
1.这是一类贪心题型,即在当前答案不变的情况下,尽可能使花费变小,让以后的状态更优;
2.细节!细节!去干净调试代码!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const ll MAXN=400001;
ll cnt=0,sum=0,n;
struct hh {ll c,w,d;}ma[MAXN];
bool operator < (hh a,hh b)
{
return a.w < b.w;
}
priority_queue<hh>q;
bool cmp(hh a,hh b)
{
return a.d < b.d;
}
void calc()
{
for(ll i=1;i<=n;i++)
{
if(ma[i].c>=sum)
cnt++,sum+=ma[i].w,q.push(ma[i]);
else
{
if(q.empty()) continue;
hh u=q.top();
if(u.w > ma[i].w)
q.pop(),sum-=u.w,sum+=ma[i].w,q.push(ma[i]);//因为i.d>u.d,而i.w<u.w,所以i.c>u.c,所以不用担心i无法承受u下面挂缀的情况;
}
}
return;
}
void solve()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld%lld",&ma[i].c,&ma[i].w);
ma[i].d=ma[i].c+ma[i].w;
}
sort(ma+1,ma+n+1,cmp);
calc();
cout<<cnt<<endl<<sum<<endl;
}
int main()
{
solve();
return 0;
}