Loading

luogu P1648 看守

题目大意

给定 \(d\) 维坐标的 \(n\) 个点,每个点表示为 \(d\) 个数值,求两点间最大距离
\(d\) 维两点间距离为 \(|x_1-y_1|+|x_2-y_2|+...+|x_d-y_d|\)

Sol

我们随便找两个点 \(A\)\(B\) 作为演示:

\[dis_{A,B}=|x_1-y_1|+|x_2-y_2|+...+|x_d-y_d| \]

\(q\)\(1\)\(-1\),其实还可以写成:

\[dis_{A,B}=(qx_1-qy_1)+...+(qx_d-qy_d) \]

(其中 \(q\) 不是同一个值)

如果这就是最大距离的话,我们改动任意一个 \(q\) 都会导致结果不优于当前结果
所以我们可以表示成:

\[\max_{q\in\{-1,1\}} \{(qx_1-qy_1)+...+(qx_d-qy_d)\} \]

可以给每个 \(q\) 单独赋值, 所得结果最大值即为最大距离

所以令 \(0\) 表示 \(1\) , \(1\) 表示 \(-1\) 压缩到一个 \(d\) 位二进制数中(跟状压dp很像)
我们只需要扫一遍 \([0,2^d-1]\) 就能找到答案
注意: 其中存在无用状态, 但一定会被最终结果覆盖

Code

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>

using namespace std;

const int N = 1e6+10;
const int INF = 0x3f3f3f3f;

int n , m;
vector<int> vec[N];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	
	cin >> n >> m;
	for(int i = 1 ; i <= n ; i ++)
		for(int j = 1 ; j <= m ; j ++) {
			int x; cin >> x;
			vec[i].push_back(x);
		}
	
	int res = 0;
	for(int state = 0 ; state < (1<<m)-1 ; state ++) {
		int minx = INF , maxx = -INF;
		for(int i = 1 ; i <= n ; i ++) {
			int v = 0;
			for(int j = 0 ; j < m ; j ++)
				if(state & (1 << j)) v += vec[i][j];
				else v -= vec[i][j];
			minx = min(minx , v);
			maxx = max(maxx , v);
		}
		res = max(res , maxx - minx);
	}
	cout << res << '\n';
	return 0;
}

闲话

在模拟赛中找到了 \(d\leq 8\) 的同款题目

posted @ 2025-10-07 16:45  lyr2023  阅读(2)  评论(0)    收藏  举报