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; }