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.因为最后的答案要最大 又答案可被分为主武器和副武器两部分 所以可直接求两部分分别的最大

状压枚举时 找出在当前枚举的加减中 答案最大的主武器 和 答案最大的副武器 然后更新答案就行

#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
",ans);
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zquzjx/p/10460890.html