P7745 [COCI2011-2012#3] ROBOT

Description

在一个平面直角坐标系中,有一个点 bot,现有四个指令,分别可以让 bot 向上、下、左、右四个方向中的一个移动一格。同时还有 \(n\) 个固定点,求每次移动后这些点到 bot 的哈曼顿距离之和。

两个点 \((x1, y1)\)\((x2, y2\) 的曼哈顿距离为 \(|x1 - x2| + |y1 - y2|\)

Solution

40 pts

每次移动后暴力求出每个点的哈曼顿距离,相加输出即可。

code

#include <bits/stdc++.h>
#define N 100005
#define int long long
using namespace std;
namespace xycyx {
	int n, m;
	int hmd[N];
	int X[N], Y[N];
	char c;
	int botx = 0, boty = 0;
	int get_hmd(int X1, int Y1) {
		return abs(X1 - botx) + abs(Y1 - boty);
	}
	void solve() {
		ios::sync_with_stdio();
		cin.tie(0);
		cin >> n >> m;
		for (int i = 1; i <= n; i++) cin >> X[i] >> Y[i];
		for (int i = 1; i <= m; i++) {
			cin >> c;
			if (c == 'S') boty++;
			if (c == 'J') boty--;
			if (c == 'I') botx++;
			if (c == 'Z') botx--;
			int ans = 0;
			for (int i = 1; i <= n; i++)
				ans += get_hmd(X[i], Y[i]);
			cout << ans << '\n';
		}
	}
}
signed main() {
	xycyx::solve();
	return 0;
} //40pts

100 pts

鉴于数据范围,时间复杂度应为 \(O(m)\),故每次查询的时间复杂度都为 \(O(1)\)

对于两条坐标轴,每次移动后分别二分求出有多少个点小于当前机器人的位置,多少点大于当前机器人的位置,求出当前移动对答案的贡献。直接更新答案并输出即可。

考虑一下每次移动造成的影响:

如果执行 S 操作,则意味着 bot 会从 移动到 \((0, 1)\) 的位置,此时明显的,对于 \(y \le y_{bot}\) 的 A、C、F 三点,哈曼顿距离分别加一;而对于 \(y > y_{bot}\) 的 B、D、E 三点而言,哈曼顿距离分别减一。即 \(y_i \le y_{bot}\) 的点在 S 操作时哈曼顿距离会增加,而 \(y_i > y_{bot}\) 的点在 S 操作时哈曼顿距离会减小。此时,答案的更新操作应为:减去移动前 \(y \le y_{bot}\) 的点的数量,加上当前 \(y \le y_{bot}\) 的点的数量。

对于剩余的三种操作同理。

可以使用 upper_boundlower_bound

code

注意先排序后再二分查找。

#include <bits/stdc++.h>
#define N 100000
#define M 300000
#define ll long long
using namespace std;
namespace cyxyc {
	int n, m;
	int X1, Y1, X2, Y2, X = 0, Y = 0;
	ll ans = 0;
	int x[N + 5], y[N + 5];
	char c[M + 5];
	int get_hmd(int x, int y) {
		return abs(x) + abs(y);
	}
	void solve() {
		ios::sync_with_stdio();
		cin.tie(0);
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			cin >> x[i] >> y[i];
			ans += get_hmd(x[i], y[i]);
		}
		cin >> c + 1;
		sort(x + 1, x + n + 1), sort(y + 1, y + n + 1); //upper_bound 和 lower_bound 都是二分查找
		X1 = upper_bound(x + 1, x + n + 1, X) - (x + 1); //第一个大于当前位置的点的下标
		X2 = lower_bound(x + 1, x + n + 1, X) - (x + 1); //第一个大于等于当前位置的点的下标
		Y1 = upper_bound(y + 1, y + n + 1, Y) - (y + 1);
		Y2 = lower_bound(y + 1, y + n + 1, Y) - (y + 1);
		for (int i = 1; i <= m; i++) {
			if (c[i] == 'S') {
				ans += 2 * Y1 - n; //ans = ans - (n - Y1) + Y1
				Y++;
				Y1 = upper_bound(y + 1, y + n + 1, Y) - (y + 1);
				Y2 = lower_bound(y + 1, y + n + 1, Y) - (y + 1);
			}
			if (c[i] == 'J') {
				ans += n - 2 * Y2;
				Y--;
				Y1 = upper_bound(y + 1, y + n + 1, Y) - (y + 1);
				Y2 = lower_bound(y + 1, y + n + 1, Y) - (y + 1);
			}
			if (c[i] == 'I') {
				ans += 2 * X1 - n;
				X++;
				X1 = upper_bound(x + 1, x + n + 1, X) - (x + 1);
				X2 = lower_bound(x + 1, x + n + 1, X) - (x + 1);
			}
			if (c[i] == 'Z') {
				ans += n - 2 * X2;
				X--;
				X1 = upper_bound(x + 1, x + n + 1, X) - (x + 1);
				X2 = lower_bound(x + 1, x + n + 1, X) - (x + 1);
			}
			printf("%lld\n", ans);
		}
	}
}
int main() {
	cyxyc::solve();
	return 0;
}
posted @ 2024-02-27 20:51  Foiled  阅读(13)  评论(0编辑  收藏  举报