NOIP模拟(10.26)T3 大逃杀

大逃杀

题目背景:

10.26 NOIP模拟T3

分析:树型DP

 

老子有句XXX真的非常想讲······我特喵的,喵了个咪的,喵喵喵喵喵!

好了发泄完了,准备说说怎么做,当时拿到这道题,第一发只想到了一个O(n4)DP,我们定义状态f[i][j][0/1]表示,在以i为根的子树中,花费j的时间,0:从i出发最终回到i的最大获利,1:从i出发最终不回到i的最大获利,然后转移比较好想了

f[i][j][0] = max(f[i][j - 1][0], f[i][k][0] + f[i][j - k - 2 * dis][0])[v表示当前枚举到的儿子,dis表示vi之间连边的消耗值,转移表示在之前枚举到的子树中走k个时间,最后回到i,然后走到vv子树中走j - k - 2 * dis的时间然后,回到i的最大获利]

f[i][j][1] = max(f[i][j - 1][1], f[i][k][0] + f[v][j - k - dis][1]) [vdis的意义同上,这个转移表示在之前的子树中,走k时间回到i,然后走到v,然后在v当中走j - k - dis的时间,不回到vi的最大获利]

f[i][j][1] = max(f[[i][j][1], f[i][k][1] + f[v][j - k - 2 * dis][0])[vdis意义同上,这个转移表示先从i走到v,在v的子树中走j - k - 2 * dis时间然后回到v,之后走到i,然后在之前的子树中走k时间,不回到i的最大获利]

显然这样只能针对一个点求出T秒的最大值·····以一个点为根,DP一次的复杂度是O(nT2)的,那么n次就是O(n2T2)最后得到了65分······

 

现在来说标算,其实标算想法很简单,我们在原来的DP基础上,再加上一种状态就好了,定义f[i][j][0/1/2]0/1状态的转移和表示同之前的DP是一样的,而f[i][j][2]表示,从i的子树中出发,最终回到i的子树内部,(起点和终点都不是i,但是会经过i),考虑如何转移这个状态。

f[i][j][2] = max(f[i][j][2], f[i][k][1] + f[v][j - k - dis][1]) [vdis的意义依然同上,这个转移的意思就是,从i之前的子树中的一个节点花费k时间来到i,然后在从iv,然后在v子树中走j - k - dis的时间,最终不回到i的最大获利]

f[i][j][2] = max(f[i][j][2], f[i][k][0] + f[v][j - k - dis * 2][2]) [vdis的意义同上,转移的意思为,从之前v子树中的一个节点走到v,然后走到i再在i之前的子树中走k个时间回到i,之后再走到v的子树中,最后不回到i的最大获利,这样说可能不清楚,请看下面这张图]

 

对应颜色的s,t表示对应路径的走法,红色的线表示的f[i][k][0]的走法,橙色的线表示的是f[v][j - k - dis * 2][2]的走法,绿色的线是两者合并的走法,所以需要减去2 * dis的时间。

f[i][j][2] = max(f[i][j][2], f[i][k][2] + f[v][j - k - 2 * dis][0]) [v,dis意义同上,这个表示从i原来的子树中的一个点出发来到i,然后从ivv的子树中走j - k - 2 * dis的时间,然后回到v,然后再走到i,最后走到i的子树当中的最大获利,图像同样在下方]

 

红色表示f[i][k][2], 橙色表示f[v][j - k - 2 *dis][0], 绿色表示两者合并。同样要减去2 * dis的时间

好了,至此2转移完成,然后我们的最终答案就是所有的f[i][T][0/1/2]的最大值·····复杂度O(n3)

 

注意:

1、显然我们在更新f[i][j][0/1/2]的时候,有调用过f[i][k][0/1/2],那么如果想要不开辅助数组,那么一定就需要倒序枚举j才行

2、因为原题数据存在一些很奇妙的情况,比如dis可以为0·····那么就可能出现,我们在倒序更新的时候会用自己更新自己,比如用f[i][j][0]更新f[i][j][2],用f[i][j][2]更新f[i][j][2],那么就涉及到一些问题,为了不让转移混乱掉,我们要做到以下几点,第一更新顺序为先更新2,再更新1,再更新0,因为2状态由0, 1, 2状态更新,1状态由0,1状态更新,0状态由0状态更新,如果先更新了0,那么可能就会出现用新更新过的0状态更新了这一次的2状态,所以顺序为2,1,0,然后第二点就是,在用不同状态更新相同状态的过程中,又有顺序,要先用自己更新自己才行,比如你先用0状态更新了2状态,那么如果你要用2状态更新2状态时,就可能用新的2状态,更新了自己本身,又会出错······所以综合下来就是说,枚举j需要倒序枚举,枚举k要倒序枚举(先用自己更新自己),然后每一次更新先用2更新2,再用0,1更新2,再用1更新1,再用0更新1,最后用0更新0······总之被坑了好久好久····

 

65DP

Source

/*
	created by scarlyw
*/
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <ctime>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = read(); !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;

inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = getchar(); !isdigit(c); c = getchar()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 300 + 10;

struct node {
	int to, w;
	node(int to = 0, int w = 0) : to(to), w(w) {}
} ;

std::vector<node> edge[MAXN];

inline void add_edge(int x, int y, int z) {
	edge[x].push_back(node(y, z)), edge[y].push_back(node(x, z));
}

int n, x, y, z, tot;
int w[MAXN], t[MAXN], f[MAXN][MAXN][2];

inline void read_in() {
	R(n), R(tot);
	for (int i = 1; i <= n; ++i) R(w[i]);
	for (int i = 1; i <= n; ++i) R(t[i]);
	for (int i = 1; i < n; ++i) R(x), R(y), R(z), add_edge(x, y, z);
}

inline void dfs1(int cur, int fa, int tt) {
	for (int i = 0; i <= tt; ++i) f[cur][i][0] = f[cur][i][1] = 0;
	int temp = tt - t[cur];
	if (temp < 0) return ;
	for (int p = 0; p < edge[cur].size(); ++p) {
		node *e = &edge[cur][p];
		if (e->to != fa) {
			dfs1(e->to, cur, temp - e->w);
			for (int i = temp; i > 0; --i) {
				f[cur][i][0] = std::max(f[cur][i - 1][0], f[cur][i][0]);
				f[cur][i][1] = std::max(f[cur][i - 1][1], f[cur][i][1]);
				for (int j = e->w; j <= i; ++j) {
					if (j >= 2 * e->w) {
						f[cur][i][0] = std::max(f[cur][i][0], 
							f[cur][i - j][0] + f[e->to][j - 2 * e->w][0]);
						f[cur][i][1] = std::max(f[cur][i][1], 
							f[cur][i - j][1] + f[e->to][j - 2 * e->w][0]);
					}
					if (j >= e->w) {
						f[cur][i][1] = std::max(f[cur][i][1], 
							f[cur][i - j][0] + f[e->to][j - e->w][1]);
					}
				}
			}
		}
	}
	for (int i = tt; i >= t[cur]; --i) {
		f[cur][i][0] = f[cur][i - t[cur]][0] + w[cur];
		f[cur][i][1] = f[cur][i - t[cur]][1] + w[cur];
	}
	for (int i = 0; i < t[cur]; ++i) f[cur][i][0] = f[cur][i][1] = 0;
}

inline void solve() {
	int ans = 0;
	for (int i = 1; i <= n; ++i) {
		dfs1(i, 0, tot);
		ans = std::max(std::max(f[i][tot][0], f[i][tot][1]), ans);
	}
	std::cout << ans;
}

int main() {
//	freopen("toyuq.in", "r", stdin);
//	freopen("toyuq.out", "w", stdout);
	read_in();
	solve();
	return 0;
}


100DP

Source

 

/*
	created by scarlyw
*/
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <ctime>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = read(); !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;

inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = getchar(); !isdigit(c); c = getchar()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 300 + 10;

struct node {
	int to, w;
	node(int to = 0, int w = 0) : to(to), w(w) {}
} ;

std::vector<node> edge[MAXN];

inline void add_edge(int x, int y, int z) {
	edge[x].push_back(node(y, z)), edge[y].push_back(node(x, z));
}

int n, x, y, z, tot;
int w[MAXN], t[MAXN], f[MAXN][MAXN][3];

inline void read_in() {
	R(n), R(tot);
	for (int i = 1; i <= n; ++i) R(w[i]);
	for (int i = 1; i <= n; ++i) R(t[i]);
	for (int i = 1; i < n; ++i) R(x), R(y), R(z), add_edge(x, y, z);
}

inline void dfs1(int cur, int fa) {
	for (int i = t[cur]; i <= tot; ++i) 
		f[cur][i][0] = f[cur][i][1] = f[cur][i][2] = w[cur];
	for (int p = 0; p < edge[cur].size(); ++p) {
		node *e = &edge[cur][p];
		if (e->to != fa) {
			dfs1(e->to, cur);
			for (int i = tot; i >= 0; --i) {
				for (int j = i - 2 * e->w; j >= t[cur]; --j) {
					f[cur][i][2] = std::max(f[cur][i][2],
						f[cur][j][2] + f[e->to][i - j - 2 * e->w][0]);
					f[cur][i][2] = std::max(f[cur][i][2], 
						f[cur][j][0] + f[e->to][i - j - 2 * e->w][2]);
				}
				for (int j = i - e->w; j >= t[cur]; --j) {
					f[cur][i][2] = std::max(f[cur][i][2], 
						f[cur][j][1] + f[e->to][i - j - e->w][1]);
				}
				for (int j = i - 2 * e->w; j >= t[cur]; --j) {
					f[cur][i][1] = std::max(f[cur][i][1], 
						f[cur][j][1] + f[e->to][i - j - 2 * e->w][0]);
				}
				for (int j = i - e->w; j >= t[cur]; --j) {
					f[cur][i][1] = std::max(f[cur][i][1], 
						f[cur][j][0] + f[e->to][i - j - e->w][1]);
				}
				for (int j = i - 2 * e->w; j >= t[cur]; --j) {
					f[cur][i][0] = std::max(f[cur][i][0], 
						f[cur][j][0] + f[e->to][i - j - 2 * e->w][0]);
				}
			}
		}
	}
}

inline void solve() {
	int ans = 0;
	dfs1(1, 0);
	for (int i = 1; i <= n; ++i)
		ans = std::max(std::max(f[i][tot][0], f[i][tot][1]), 
			std::max(ans, f[i][tot][2]));
	std::cout << ans;
}

int main() {
//	freopen("toyuq.in", "r", stdin);
//	freopen("toyuq.out", "w", stdout);
	read_in();
	solve();
	return 0;
}

内容概要:本文详细介绍了使用KGDB(Kernel GNU Debugger)调试Linux内核的方法及其重要性。文章首先强调了Linux内核作为系统核心的重要性及其调试的必要性,随后介绍了KGDB的基本原理和优势,包括其基于调试stub和GDB串行协议的工作机制。接着,文章详细描述了使用KGDB调试内核的具体步骤,包括准备工作、内核配置、设置启动参数、建立调试连接和进行调试操作。文中还通过一个实战案例展示了KGDB在解决实际问题中的应用,并总结了使用KGDB时的注意事项和常见问题的解决方法。最后,文章展望了KGDB未来的发展方向和应用场景,如优化调试性能、支持新硬件架构以及在嵌入式系统、云计算和大数据领域的应用。 适合人群:具备一定Linux系统开发经验的研发人员,尤其是那些需要调试和优化Linux内核的工程师。 使用场景及目标:①帮助开发者深入了解Linux内核的运行状态,精准定位并修复内核问题;②优化内核性能,提高系统的稳定性和可靠性;③适用于嵌入式系统开发、远程服务器维护等场景,特别是在硬件资源有限或无法直接接触设备的情况下。 其他说明:在使用KGDB进行调试时,需特别注意串口设置的一致性、内核版本的兼容性以及调试信息的完整性。同时,要解决常见的连接失败、断点无效等问题,确保调试过程顺利进行。未来,KGDB有望在技术上不断优化,并拓展到更多应用场景中,为Linux系统的持续发展提供支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值