\(Preface\)
最近咋老考贪心嘞?我的数据结构呢?
贪心这玩意确实重要。但是我蒟蒻,老做不出来,而且经常写挂某些需要用到一些小技巧的题。。。
具体地,刷贪心题既是刷思维也是刷能力。
其实就是刷水题来了
\(\mathfrak{Luogu\ P1007}\ 独木桥\)
还是第一篇题解说的那样,从高空看两个人相遇之后回头继续走,看起来就像两个人互相穿过了一样。
然而确实是这样的。两个人相遇后回头,就等同于各走各的继续走。
直接对于每一个人往左和往右走分别取min
max
就行了。
注意几个人是同时在走的,所以在原来分别取min
max
的同时,对所有人走出去需要的时间取一个max
即为答案。
$Luogu-P1007$
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
/*
不知道贪心对不对
mid:len>>1
最优:
<= mid:->左
> mid: ->右
最劣:
<= mid
谔 这好像不是很水的贪心?
*(康题解)*
超!
*/
int len, n, mnans, mxans;
inline void work(){
cin >> len >> n;
for (re i = 1, plc ; i <= n ; ++ i)
{cin >> plc; mnans = MAX(mnans, MIN(plc, len-plc+1)), mxans = MAX(mxans, MAX(plc, len-plc+1));}
cout << mnans << _ << mxans << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{Luogu\ P2240} 【深基12.例1】部分背包问题\)
按照性价比排序,选就行了。题目都提示的这么明显了。。。
分割完的金币重量价值比(也就是单位价格)不变。
$Luogu-P2240$
#include <iostream>
#include <algorithm>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 105
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
struct node{
int m, w; double cpr;
friend bool operator < (node A, node B){return A.cpr > B.cpr;}
};
/*
题干直接说做法了这
性价比排个序就完事了
*/
int n, capacity;
double final_ans;
struct node a[N];
inline void work(){
cin >> n >> capacity;
for (re i = 1 ; i <= n ; ++ i)
{cin >> a[i].m >> a[i].w; a[i].cpr = (double)a[i].w/a[i].m;}
sort(a+1, a+n+1);
for (re i = 1 ; i <= n ; ++ i){
if (capacity - a[i].m < 0)
{final_ans += capacity * a[i].cpr; capacity = 0; break;}
else
final_ans += a[i].w, capacity -= a[i].m;
}
cout.setf(ios::fixed), cout.precision(2);
cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a, a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{Luogu\ P1223}\ 排队接水\)
显然让接水时间短的先接。注意他问的是等待时间的平均值,不用算上本身接水的时间。
记得开long long
$Luogu-P1223$
#include <iostream>
#include <algorithm>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 1005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
struct Person{
int ai, id;
friend bool operator < (Person A, Person B){
return A.ai < B.ai;
}
};
/*
直接按照ti sort一遍即可
*/
int n;
long long final_ans;
struct Person a[N];
inline void work(){
cin >> n;
for (re i = 1 ; i <= n ; ++ i)
{cin >> a[i].ai; a[i].id = i;}
sort(a+1, a+n+1);
for (re i = 1, j = n-1 ; i <= n ; ++ i, -- j){
final_ans += (long long)a[i].ai*j;
}
for (re i = 1 ; i <= n ; ++ i)
cout << a[i].id << _;
Endl;
/*for (re i = 1 ; i <= n ; ++ i)
cerr << a[i].ai << _;
Dl;*/
cout.setf(ios::fixed), cout.precision(2);
cout << ((long double)final_ans/n) << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a, a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{Luogu\ P1803}\ 凌乱的yyy / 线段覆盖\)
考虑下面的情况:
|<------------------->|
|<----->| |<---->|
显然选第二行的更优。
那么就有了较为朴素的 \(dp\) 转移想法,既 \(check\) 某一个区间是否能够被更多的区间所替代,相应地选择是否更新 \(dp\) 值。
其实是不需要 \(dp\) 的,直接 \(sort\) 右端点去选就行了
$Luogu-P1803$
#include <iostream>
#include <algorithm>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 1000005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
struct XD{
int ai, bi;
friend bool operator < (XD A, XD B){return A.bi < B.bi;}
};
/*
直接题目映射做法是吧
似乎是维护线段覆盖,使得连续的线段能够最长
*(看题解)*
没看懂
问kirito
好家伙直接一个反证法证出来了
考虑这样的情况
|<-------------->|
|<-->| |<---->|
显然选下面的更优
所以直接求出来当前点的最优解,用此最优解去更新下一个最优解
没错,dp
但是不用dp就能实现,sort右端点就行了
*/
int n, final_ans;
struct XD a[N];
inline void work(){
cin >> n;
for (re i = 1 ; i <= n ; ++ i)
cin >> a[i].ai >> a[i].bi;
sort(a+1, a+n+1);
int plc = a[1].bi;
final_ans = 1;
for (re i = 2 ; i <= n ; ++ i)
if (a[i].ai >= plc)
plc = a[i].bi, final_ans ++;
cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a, a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{Luogu\ P1090}\ [NOIP2004 提高组]\ 合并果子\ /\ [USACO06NOV]\ Fence\ Repair\ G\)
虎哥讲过。而且很简单吧。。远古时期的水题
直接贪心地先让最小的合并,用一个set
维护最小值,然后合并之后再扔进set
,最后set
里元素就剩一个的时候break
,期间统计答案即可。
$Luogu-P1090$
#include <iostream>
#include <set>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#define re register int
#define char_phi signed
#define DMARK cerr << "###"
#define _ ' '
#define Endl cout << '\n'
#define Dl cerr << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
/*
那显然是先合并最小的?
用一个multiset维护就行了
*/
int n, final_ans;
multiset<int> s;
inline void work(){
cin >> n;
if (n == 0)
return ;
for (re i = 1, w ; i <= n ; ++ i)
{cin >> w; s.insert(w);}
while (s.begin() != prev(s.end())){
int w1 = *s.begin(); s.erase(s.begin());
int w2 = *s.begin(); s.erase(s.begin());
final_ans += w1+w2;
s.insert(w1+w2);
}
cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a, a);
#endif
Fastio_setup();
work();
return GMY;
}