hdu 6435 /// 状压
题目大意:
给定 n m k 为 n种主武器 m种副武器 武器有k种属性
接下来n行 先给定当前主武器的综合分s1 再给定k种属性的值
接下来m行 先给定当前副武器的综合分s2 再给定k种属性的值
要求选定一种主武器配一种副武器 使得 s1+s2+k种属性的差值的绝对值之和
T<=100, n<=100000, m<=100000, K<=5, 0<=S<=1e9, |x[i]|<=1e9, sum of (n+m)<=300000
k的范围只有5 状压枚举每种属性的加减
即 若主武器有三种属性a b c 副武器A B C(设a>A b<B c>C)
那么差值的绝对值就是 a-A + B-b + c-C = a-b+c + (-A+B-C) = 主武器部分 + 副武器部分
1.因为是求差值的绝对值 会发现当主武器某属性是 + 那么副武器对应属性就应该是 -
2.因为实际上所有属性的大小关系未知 所以枚举加减来可找到最大的一种
(01分别对应主武器的加减 则副武器与主武器相反10分别表示加减)
3.因为最后的答案要最大 又答案可被分为主武器和副武器两部分 所以可直接求两部分分别的最大
状压枚举时 找出在当前枚举的加减中 答案最大的主武器 和 答案最大的副武器 然后更新答案就行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; #define LL long long #define INF 0x3f3f3f3f #define mem(i,j) memset(i,j,sizeof(i)) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int N=1e5+5; const int mod=1e9+7; int n,m,k; LL v1[N][10], v2[N][10]; LL s1[N], s2[N]; int main() { int _; scanf("%d",&_); while(_--) { scanf("%d%d%d",&n,&m,&k); inc(i,1,n) { scanf("%lld",&s1[i]); inc(j,1,k) scanf("%lld",&v1[i][j]); } inc(i,1,m) { scanf("%lld",&s2[i]); inc(j,1,k) scanf("%lld",&v2[i][j]); } int task=(1<<k)-1; LL ans=-INF; inc(s,0,task) { LL max1=-INF; inc(i,1,n) { LL tmp1=s1[i]; inc(j,1,k) if((1<<j-1)&s) tmp1+=v1[i][j]; else tmp1-=v1[i][j]; max1=max(max1,tmp1); } LL max2=-INF; inc(i,1,m) { LL tmp2=s2[i]; inc(j,1,k) if((1<<j-1)&s) tmp2-=v2[i][j]; else tmp2+=v2[i][j]; max2=max(max2,tmp2); } ans=max(ans,max1+max2); } printf("%lld\n",ans); } return 0; }