版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiang_6/article/details/81951257
题意:
给定 n个物品A 和 m个物品B;每个物品都有一个值 s 和 k 个属性值 x[i],
问:从n个物品中选一个 i,m个物品里选一个 j,ans = i_s + j_s + Sigma( | i_x[t] - j_x[t] | , t : [0,k-1] ); 求 ans 的最大值
思路:
如果 Sigma部分求差值绝对值哪里不是绝对值的话,那样对于 i 物品中 x[i] 全部求和就OK了;
现在加上绝对值后我们不知道绝对值后的值是什么,但是我们能确定的是 |a-b| = a-b 或者 b-a,这两种情况
所以我们可以把最大ans 式子看做: i_s + j_s + (# * i_x[0]) + (# * i_x[1]) ... + (# * i_x[k-1]) + (# * j_x[0]) + ... (# * j_x[k-1]);
其中 # 表示正负号, 即 物品 i - j 时,相对应的 x[t] 可能是本身相减,也可能同时变负后相减,即每个 x[t] 对应了两种情况,至于k个属性,那就是 2^k 中不同的状态,
这些状态中, 每个从n个中取最大值,然后计算m个物品中的每种状态的值,用n个中最大的减去,取最大值
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int maxd = 30 + 7;
struct node {
ll s;
ll x[6];
ll t[maxd];
}a[maxn], b[maxn];
ll max_[maxd];
ll ans[maxd];
int main() {
int T; scanf("%d", &T);
while(T--) {
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
memset(max_, 0, sizeof max_);
int k_ = (1<<k);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i].s);
for(int j = 0; j < k; ++j) {
scanf("%lld", &a[i].x[j]);
}
for(int j = 0; j < k_; ++j) {
ll t = a[i].s;
for(int pos = 0; pos < k; ++pos) {
if(j&(1<<pos)) {
t += (-1)*(a[i].x[pos]);
}
else t += a[i].x[pos];
}
max_[j] = max(max_[j], t);
}
}
memset(ans, 0, sizeof ans);
for(int i = 1; i <= m; ++i) {
scanf("%lld", &b[i].s);
for(int j = 0; j < k; ++j) {
scanf("%lld", &b[i].x[j]);
}
for(int j = 0; j < k_; ++j) {
ll t = -b[i].s;
for(int pos = 0; pos < k; ++pos) {
if(j&(1<<pos)) {
t += (-1)*(b[i].x[pos]);
}
else t += (b[i].x[pos]);
}
ans[j] = max(ans[j], max_[j]-t);
}
}
ll anss = 0;
for(int i = 0; i < k_; ++i) {
anss = max(anss, ans[i]);
}
printf("%lld\n", anss);
}
return 0;
}