抄题解 题解

  1. 1. Solution

Solution

观察题面,由数据范围可知这道题的复杂度为 O(n log n) 作法为贪心。

如何贪心呢?

在与 @ryanright 的交往中,认识到一点他的做题技巧:

1、能做的题先做;

2、做不了的选择最高收益的做。

所以,就能通过优先队列写出下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct Node{
int a,b,c;
bool used;
};
vector<Node> v;
struct Node1{
int a,b,c,id;
bool operator < (Node1 b) const
{
return (this->a)>b.a;
}
};
struct Node2{
int a,b,c,id;
bool operator < (Node2 b) const
{
return (this->b)-(this->c)<b.b-b.c;
}
};
priority_queue<Node1> p1;
priority_queue<Node2> p2;

#define gc getchar()
template<typename T>
void read(T&r)
{
r=0;
char ch=gc,last='z';
while(ch<'0'||ch>'9') last=ch,ch=gc;
while(ch>='0'&&ch<='9') r=r*10+ch-'0',ch=gc;
if(last=='-') r=-r;
}

signed main(signed argc,char* argv[])
{
// string file=argv[1];
// string filein=file+".in",fileout=file+".out";
// freopen(filein.c_str(),"r",stdin);
// freopen(fileout.c_str(),"w",stdout);
int T,V,n,a,b,c;
read(T);
while(T--)
{
v.clear();
while(!p1.empty()) p1.pop();
while(!p2.empty()) p2.pop();
read(V),read(n);
for(int i=0;i<n;i++)
{
read(a),read(b),read(c);
v.push_back({a,b,c,0});
p1.push({a,b,c,i});
p2.push({a,b,c,i});
}
for(int i=0;i<n;i++)
{
Node1 t1=p1.top();
while(v[t1.id].used) p1.pop(),t1=p1.top();
Node2 t2=p2.top();
while(v[t2.id].used) p2.pop(),t2=p2.top();
//有可能在其他队列中使用过了,要过滤掉
if(V>=t1.a)
{
V+=t1.b;
v[t1.id].used=true;
p1.pop();
}
else
{
V+=t2.b-t2.c;
v[t2.id].used=true;
p2.pop();
}
}
printf("%d\n",V);
}
return 0;
}

不过这是否正确呢?

证明:

1、优先做能做的(能力值范围内的)是必须的。

能做的,不会降低能力(注意 ),且之后的题目会有更高的收益。

2、做不了能做的,就做收益最高的,也是必须的。

没有能做的,就代表不一定会增加能力。当增加为正时,相对于其他题目,会让后面有更多的收益;增加为负时,相对于其他题目,会让后面做的题扣的能力更少。

/kk