UVa:1508 Equipment

K大于等于5的时候很好想,只要每一项都取最大值相加即可。

但是小于5的时候就不太好做了。

我一开始想了一个思路,认为选的K个type在这5种r中每个一定有一种是最大的。

但是

6 1
2 2 2 2 2
3 2 2 1 1
2 3 2 1 1
2 2 3 1 1
1 1 2 3 2
1 1 2 2 3

这组数据就过不了,正确答案应该是10。

好在数据量并不大,可以无脑枚举。

枚举要从这5种r的角度出发。这5种r可以由K个tpye组成,所以可以预处理5种r的子集在N种type里面的最大值。然后dfs枚举子集,取K个,选最大值。

如果从N种type'的角度考虑会无从下手。从5种r的角度考虑就能轻松解决,确实非常巧妙。。

 

关于位运算的一些运算:

(i-1)&sup  i表示sup的子集 (i从sup到0)

如果i是sup的子集 sup^i表示从sup中除去i

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define MOD 20071027
#define MAXN 255
using namespace std;
int maxn[100];
struct R
{
    int a[10];
};
vector<R> vec;
int n,K;
int ans;
void dfs(int S,int cur,int sum)
{
    if(cur==K) ans=max(sum,ans);
    else
    {
        for(int i=S;i;i=(i-1)&S)
         dfs(S^i,cur+1,sum+maxn[i]);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ans=0;
        scanf("%d%d",&n,&K);
        vec.clear();
        for(int i=0; i<n; ++i)
        {
            int a,b,c,d,e;
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
            vec.push_back(R {a,b,c,d,e});
        }
        if(K>=5)
        {
            for(int i=0; i<5; ++i)
            {
                int res=0;
                for(int j=0; j<n; ++j)
                    res=max(res,vec[j].a[i]);
                ans+=res;
            }
        }
        else
        {
            memset(maxn,0,sizeof(maxn));
            for(int i=0; i<n; ++i)
            {
                for(int j=0; j<32; ++j)
                {
                    int sum=0;
                    for(int k=0; k<5; ++k)
                        if(j&(1<<k)) sum+=vec[i].a[k];
                    maxn[j]=max(maxn[j],sum);
                }
            }
            dfs(31,0,0);
        }
        printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值