美团笔试

1.模拟题,分别对RBG每个位置往左往右找即可。

2.凑颜色,直接二分答案,因为是无环转换,因此可以直接从a转换到b,再从b转换到c。

using ll = long long;
void solve() {
	int a, b, c;
	int x, y;
	cin >> a >> b >> c;
	cin >> x >> y;

	auto check = [&](int k) {
		ll reta = a, retb = b, retc = c;
		ll resa = max(0ll, reta - k);
		retb += resa / x;
		ll resb = max(0ll, retb - k);
		retc += resb / y;
		return min({reta, retb, retc}) >= k;
	};

	int l = 0, r = (int)1e9;
	while (l <= r) {
		int m = (l + r) >> 1;
		if (check(m)) {
			l = m + 1;
		} else {
			r = m - 1;
		}
	}
	cout << l - 1 << '\n';
}

3.

题目描述:

输入n q x y(定义权值数组为a),表示有n个点,q个询问,如果a[nxt[i]] > a[i],则+x, 否则+y, x和y可能是负数,

第二行输入nxt数组,表示i->nxt[i]有一条边

然后第三行输入权值数组a

接下来又q(1e5)个询问,每个询问给出ui和ki表示从ui起始最多跳ki步能取得的最大和是多少?

1<=ui<=n 1<=ki<=1e9

解题思路:考虑k太大不可能直接去模拟每一步,因此我们只需要考虑贡献的计算。

考虑把k按2进制拆分,这样去算贡献,然后合并,那么这个问题就变成了从每个点开始走(2^j)-1步能取得的最大和是多少?

这个我们考虑st表构建的过程,比较类似,也是贡献合并,因此我们的状态就设计出来了。

定义

f[i][j]:i这个点跳2^j - 1步到哪?

g[i][j]: i这个点跳2^j-1步最大贡献是多少?

比较显然的是f[i][j]的转移

f[i][j] = f[f[i][j - 1][j - 1]

接下来是考虑维护g[i][j],考虑合并两个节点时,最大贡献有什么情况呢?

1.可能原本就是左节点的答案

2.可能是原本左节点的和+右节点的靠左端的最大值和

那么我们把g[i][j]的最大值维护就想明白了。

我们需要同时维护左端最大和,该节点的总和,该节点的答案。

代码实现:

using ll = long long;
const int N = 2e5 + 5;
const int B = 31;

int f[N][B];
struct Node {
	ll lmx, tmx;
	ll s;
}g[N][B];

void solve() {
	int n, q;
	int x, y;
	cin >> n >> q;
	cin >> x >> y;

	vector<int> nxt(n + 1), a(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> nxt[i];
	}

	auto merge = [&](Node &lhs, Node &rhs) {
		Node t;
		t.tmx = lhs.tmx;
		t.lmx = max(lhs.lmx, lhs.s + rhs.lmx);
		t.tmx = max(t.tmx, t.lmx);
		t.s = lhs.s + rhs.s;
		return t;
	};
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}

	for (int i = 1; i <= n; i++) {
		f[i][0] = nxt[i];
		if (a[nxt[i]] > a[i]) {
			Node gt;
			gt.lmx = x;
			gt.tmx = x;
			gt.s = x;
			g[i][0] = gt;
		} else {
			Node gt;
			gt.lmx = y;
			gt.tmx = y;
			gt.s = y;
			g[i][0] = gt;
		}
	}
	for (int i = 1; i <= 30; i++) {
		for (int j = 1; j <= n; j++) {
			g[j][i] = merge(g[j][i - 1], g[f[j][i - 1]][i - 1]);
			f[j][i] = f[f[j][i - 1]][i - 1];
		}
	}

	auto query = [&](int u, int k) {
		Node t = {0, 0, 0};
		ll ret = 0;

		for (int i = 30; i >= 0; i--) {
			if (k >> i & 1) {
				t = merge(t, g[u][i]);
				u = f[u][i];
			}
			ret = max(ret, t.tmx);
		}
		return ret;
	};
	while (q--) {
		int u, k;
		cin >> u >> k;
		cout << query(u, k) << '\n';
	}
}

#美团##美团笔试#
全部评论
感谢大佬
1 回复 分享
发布于 09-15 14:11 北京
第二题是怎么想到二分的呀,没想到用二分...
1 回复 分享
发布于 09-15 19:21 湖南
凯哥tql
点赞 回复 分享
发布于 09-15 10:22 湖南

相关推荐

1 5 评论
分享
牛客网
牛客企业服务