贪心杂题

Preface

最近咋老考贪心嘞?我的数据结构呢?

贪心这玩意确实重要。但是我蒟蒻,老做不出来,而且经常写挂某些需要用到一些小技巧的题。。。

具体地,刷贪心题既是刷思维也是刷能力。

其实就是刷水题来了

Luogu P1007 

还是第一篇题解说的那样,从高空看两个人相遇之后回头继续走,看起来就像两个人互相穿过了一样。

然而确实是这样的。两个人相遇后回头,就等同于各走各的继续走。

直接对于每一个人往左和往右走分别取min max就行了。

注意几个人是同时在走的,所以在原来分别取min max的同时,对所有人走出去需要的时间取一个max即为答案。

LuoguP1007
#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;
}

Luogu P224012.1

按照性价比排序,选就行了。题目都提示的这么明显了。。。

分割完的金币重量价值比(也就是单位价格)不变。

LuoguP2240
#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;
}

Luogu P1223 

显然让接水时间短的先接。注意他问的是等待时间的平均值,不用算上本身接水的时间。

记得开long long

LuoguP1223
#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;
}

Luogu P1803 yyy/线

考虑下面的情况:

|<------------------->|
|<----->|  |<---->|

显然选第二行的更优。

那么就有了较为朴素的 dp 转移想法,既 check 某一个区间是否能够被更多的区间所替代,相应地选择是否更新 dp 值。

其实是不需要 dp 的,直接 sort 右端点去选就行了

LuoguP1803
#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;
}

Luogu P1090 [NOIP2004]  / [USACO06NOV] Fence Repair G

虎哥讲过。而且很简单吧。。远古时期的水题

直接贪心地先让最小的合并,用一个set维护最小值,然后合并之后再扔进set,最后set里元素就剩一个的时候break,期间统计答案即可。

LuoguP1090
#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;
}

Luogu P3817A

设点对 (i,j) 表示 ai+aj>x,那么显然我们优先把那种同时被包含在两个点对里的数削减, 暂且称为 『dbx点』。

sort一遍然后判断可以实现,但是太麻烦。

直接在读入的时候大于 x 时就削减,因为他如果和右边要读入的构成了新的点对,那么削减他是符合『优先削减『dbx点』』的。如果他和右边没有构成新的点对,那么其实削减他和削减右边要读入的点是等同的,不妨就削减他。

LuoguP3817
#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))
#define N 100005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL);}
struct Dui{int l, r;};
/*
	又滚来刷水题了
	应该是从2~n-1依次考虑是否要吃
	阿不对 从大到小吃
	然后如果说是1和n的尽量别吃
	不过似乎是找到需要吃的一对数,然后看谁能够左右两边的话就优先吃谁
	*(瞟题解)*
	我是shab
*/

int n, duicnt, x, a, b;
long long final_ans;

inline void work(){
	cin >> n >> x;
	cin >> b;
	for (re i = 2 ; i <= n ; ++ i){
		cin >> a;
		if (a+b > x)
			final_ans += (a+b-x), a -= (a+b-x);
		b = a;
	}
	cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
	#ifdef IXINGMY
		FBI_OPENTHEDOOR(a, a);
	#endif
	Fastio_setup();
	work();
	return GMY;
}

Luogu P1106 

没猜错的话是优先选择合法的最小的最高位,然后依次选择次高位等等。似乎可以爆搜实现,但是构造数据可能会T。

所以我就没写

posted @   char_phi  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示