题解:CF977D Vanya and Treasure

显然的,我们按照开箱子的顺序,记录 \(f_{x, y, p}\) 表示我开某一个 p 类型的箱子后,我站在 \((x, y)\) 上。
这个的转移是我去枚举我下一个类型的箱子开哪个。

然后这个东西发现他的转移会被卡到 \(O(nm)\) 就烂掉了。

我们考虑一个经典的东西,我么看到这种曼哈顿距离可以考虑四个象限来想,分别维护四个象限的前缀最小值。

这个东西用二维前缀和维护不了,但是我们可以扫描线或者二位树状数组来做,注意初始化的手法,不要忘记抹去最开始写的一些东西

#include <bits/stdc++.h>
using namespace std;

//#define int long long

const int N = 305;

int n, m, p;
int a[N][N];
map<int, vector<pair<int, int>>> dot;

struct tree {
	int minn[N][N];
	int lowbit(int x) {
		return x & (-x);
	}
	void init() {
		for (int i = 1;i <= n;i++) {
			for (int j = 1;j <= m;j++) {
				minn[i][j] = 0x3f3f3f3f;
			}
		}
	}
	void add(int x, int y, int d) {
		for (int i = x;i <= n;i += lowbit(i)) {
			for (int j = y;j <= m;j += lowbit(j)) {
				minn[i][j] = min(minn[i][j], d);
			}
		}
	}
	void cover(int x, int y) {
		for (int i = x;i <= n;i += lowbit(i)) {
			for (int j = y;j <= m;j += lowbit(j)) {
				minn[i][j] = 1e9;
			}
		}
	}
	int query(int x, int y) {
		int res = 1e9;
		for (int i = x;i;i -= lowbit(i)) {
			for (int j = y;j;j -= lowbit(j)) {
				res = min(res, minn[i][j]);
			}
		}
		return res;
	}
}lu, ld, ru, rd;

int f[N][N];

signed main() {
	
	cin >> n >> m >> p;
	for (int i = 1;i <= n;i++) {
		for (int j = 1;j <= m;j++) {
			cin >> a[i][j];
			dot[a[i][j]].push_back({i, j});
		}
	}
	lu.init();
	ld.init();
	ru.init();
	rd.init();
	lu.add(1, 1, -2);
//	ld.add(1, 1, 0);
//	ru.add(1, 1, 0);
//	rd.add(1, 1, 0);
	for (int i = 1;i <= p;i++) {
		for (auto j : dot[i]) {
			int x = j.first;
			int y = j.second;
			
			int cur = 1e9;
			// 1. p-1 在左上
			// f[i][j] = i + j + (f - i' - j')
			cur = min(cur, x + y + lu.query(x, y));
			// 2. p-1 在左下
			// f[i][j] = -i + j + (f + x - y)
			cur = min(cur, -x + y + ld.query(n - x + 1, y));
			// 3. p-1 在右上
			// f[i][j] = i - j
			cur = min(cur, x - y + ru.query(x, m - y + 1));
			// 4. p-1 在右下
			// f[i][j] = -i -j
			cur = min(cur, -x - y + rd.query(n - x + 1, m - y + 1));
			
			f[x][y] = cur;
		}
		for (auto j : dot[i - 1]) {
			int x = j.first;
			int y = j.second;
			lu.cover(x, y);
			ld.cover(n - x + 1, y);
			ru.cover(x, m - y + 1);
			rd.cover(n - x + 1, m - y + 1);
		}
		if (i == 1) lu.cover(1, 1);
		for (auto j : dot[i]) {
			int x = j.first;
			int y = j.second;
			int cur = f[x][y];
			lu.add(x, y, cur - x - y);
			ld.add(n - x + 1, y, cur + x - y);
			ru.add(x, m - y + 1, cur - x + y);
			rd.add(n - x + 1, m - y + 1, cur + x + y);
//			cout << x << " " << y << ": " << cur << "\n";
		}
//		cout << "\n";
	}
	int ans = 0x3f3f3f3f;
	for (auto j : dot[p]) {
		int x = j.first;
		int y = j.second;
		ans = min(ans, f[x][y]);
	}
	cout << ans;
	return 0;
}
posted @ 2025-10-03 14:42  yanbinmu  阅读(6)  评论(0)    收藏  举报