HDU

题目大意:有两类武器(主武器和副武器),每类有若干把,每把武器都有一个基础属性S,以及k个附加属性,让你选一把主武器M和一把副武器S,使得最大。

显然后面的和式是一个k维的曼哈顿距离,带绝对值符号不好算,因此要想办法把绝对值去掉。由于两点任意一个维度(设其值分别为a,b)的曼哈顿距离要么是a-b,要么是b-a,符号总是相反的,因此可以二进制枚举每一维的正负号,对主武器取最大值,对副武器取最小值,两者相减就可以得到最大的曼哈顿距离。中间可能有的值不合法,但不合法的值一定不是最优值,因此可以忽略。

至于基础属性,只要对主武器加上S,对副武器减去S就行了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e5+10,inf=0x3f3f3f3f3f3f3f3fll;
 5 int n,m,k,a[N][6],b[N][6],Log[N];
 6 ll Sa[N][1<<5],Sb[N][1<<5];
 7 int main() {
 8     Log[0]=-1;
 9     for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1;
10     int T;
11     for(scanf("%d",&T); T--;) {
12         scanf("%d%d%d",&n,&m,&k);
13         for(int i=0; i<n; ++i) {
14             scanf("%d",&a[i][k]);
15             for(int j=0; j<k; ++j)scanf("%d",&a[i][j]);
16         }
17         for(int i=0; i<m; ++i) {
18             scanf("%d",&b[i][k]);
19             for(int j=0; j<k; ++j)scanf("%d",&b[i][j]);
20         }
21         for(int i=0; i<n; ++i) {
22             for(int S=0; S<(1<<k); ++S)Sa[i][S]=0;
23             for(int j=0; j<k; ++j)Sa[i][0]+=a[i][j];
24             Sa[i][0]+=a[i][k];
25         }
26         for(int i=0; i<m; ++i) {
27             for(int S=0; S<(1<<k); ++S)Sb[i][S]=0;
28             for(int j=0; j<k; ++j)Sb[i][0]+=b[i][j];
29             Sb[i][0]-=b[i][k];
30         }
31         for(int S=1; S<(1<<k); ++S) {
32             for(int i=0; i<n; ++i)Sa[i][S]=Sa[i][S^(1<<Log[S])]-2*a[i][Log[S]];
33             for(int i=0; i<m; ++i)Sb[i][S]=Sb[i][S^(1<<Log[S])]-2*b[i][Log[S]];
34         }
35         ll ans=0;
36         for(int S=0; S<(1<<k); ++S) {
37             ll mx=~inf,mi=inf;
38             for(int i=0; i<n; ++i)mx=max(mx,Sa[i][S]);
39             for(int i=0; i<m; ++i)mi=min(mi,Sb[i][S]);
40             ans=max(ans,mx-mi);
41         }
42         printf("%lld
",ans);
43     }
44     return 0;
45 }
原文地址:https://www.cnblogs.com/asdfsag/p/11662541.html