hdu6435 CSGO 常数级别维度枚举

链接:

CSGO: http://acm.hdu.edu.cn/showproblem.php?pid=6435

题意:

有A和B两种武器,每个武器本身有价值S和k个不同属性x[1],x[2]…x[k]
现给出n件A和m件B的信息,要求从中找出一个A和一个B使得下图值最大
所求公式

数据规模:

T<=100, n<=100000, m<=100000, K<=5, 0<=S<=1e9, |x[i]|<=1e9, sum of (n+m)<=300000

思路:

一开始没看到绝对值符号,觉得Σ(xa[i]-xb[i]) = Σxa[i] - Σxb[i]乱写一发果断WA

这个问题的突破口其实在K的大小,K <= 5,把Σ| xa[i] - xb[i] |展开应该有许多的+,-号,且xa[i]前的+号 == xb[i]前的-号,反之亦然。可以通过枚举xa[i]前面的符号可能情况,比如:
+xa[1]+xa[2]-xa[3]-xa[4]+xa[5]
对应符号互补的xb[i]的对应方案:
-xb[1]-xb[2]+xb[3]+xb[4]-xb[5]

这样的话,对每一件装备,可能产生2^k种总属性值[S+X,(X = Σ±x[i],X有2^k种)],最终2^k种方案里最大属性值记录下来,当作这种符号分配方案能产生的最大的值。两种装备(A/B)符号互补的分配方案对应的最大属性值加和起来即为最终答案。

标程:

#include<bits/stdc++.h>
using namespace std;
#define LL long long

int T,n,m,K,val,x[6];
LL A[64],B[64],Ans;

int main()
{
    int i,k,S;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d",&n,&m,&K);
        Ans=0;
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));

        for (i=1;i<=n;i++)
        {
            scanf("%d",&val);
            for (k=0;k<K;k++)
                scanf("%d",&x[k]);
            for (S=0;S<1<<K;S++)
            {
                LL Sum=val;
                for (k=0;k<K;k++)
                    Sum+=x[k]*((((S>>k)&1)<<1)-1);
                A[S]=max(A[S],Sum);
            }
        }

        for (i=1;i<=m;i++)
        {
            scanf("%d",&val);
            for (k=0;k<K;k++)
                scanf("%d",&x[k]);
            for (S=0;S<1<<K;S++)
            {
                LL Sum=val;
                for (k=0;k<K;k++)
                    Sum+=x[k]*((((S>>k)&1)<<1)-1);
                B[S]=max(B[S],Sum);
            }
        }

        for (S=0;S<1<<K;S++)
            Ans=max(Ans,A[S]+B[(1<<K)-1-S]);
        printf("%lld\n",Ans);
    }
}

自写代码:

#include <bits/stdc++.h> 
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int p1[100010][6],p2[100010][6];
ll maa[65],mia[65],mab[65],mib[65];
inline void gmax(ll &a,ll b){
    if(a < b)a = b;
}
inline void gmin(ll &a,ll b){
    if(a > b)a = b;
}
int main(){
    int T,n,m,k;
    scanf("%d",&T);
    while(T--){
        ll ans = -INF;
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 0;i < n;i++)
        for(int j = 0;j <= k;j++)
        scanf("%d",&p1[i][j]);
        for(int i = 0;i < m;i++)
        for(int j = 0;j <= k;j++){
            scanf("%d",&p2[i][j]);
            if(!j)p2[i][j]*=-1;
        }
        fill(maa,maa + sizeof(maa)/sizeof(ll),-INF);
        fill(mab,mab + sizeof(mab)/sizeof(ll),-INF);
        fill(mia,mia + sizeof(mia)/sizeof(ll),INF);
        fill(mib,mib + sizeof(mib)/sizeof(ll),INF);
        for(int i = 0;i < n;i++)
        for(int j = 0;j < 2<<k;j++){
            ll sum = 0;
            for(int t = 0;t <= k;t++)
            if(j & (1<<t))sum += p1[i][t];
            else sum -= p1[i][t];
            gmax(maa[j],sum);
            gmin(mia[j],sum);
        }
        for(int i = 0;i < m;i++)
        for(int j = 0;j < 2<<k;j++){
            ll sum = 0;
            for(int t = 0;t <= k;t++)
            if(j & (1<<t))sum += p2[i][t];
            else sum -= p2[i][t];
            gmax(mab[j],sum);
            gmin(mib[j],sum);
        }
        for(int i = 0;i < 2<<k;i++)
        gmax(ans,maa[i] - mib[i]),gmax(ans,mab[i] - mia[i]);
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/krypton12138/article/details/82017146
今日推荐