题意:给定n件主武器,m件副武器,每件主武器和副武器分别拥有各自的分数s和k个属性x[1]、x[2]...x[k]。从中选择一件主武器和一件副武器使得最大。
因为k至多为5,这道题一眼看上去大概能猜到时间复杂度应该是,然后突然想到一道以前见过有一丢丢类似的题。
当然,这两道题的要求还是有所不同的。
Nowcoder Girl的某道题的题解
想到了时间复杂度之后,这个是从哪里来的呢?假设主武器某些属性值大于副武器,其余属性值小于副武器,一共有种可能。不论如何,最后的答案应该是s1+s2+sum(较大的属性-较小的属性)。那么我们枚举种情况时,不管是对于主武器还是副武器,相当于我们已知该项属性值是应该被加上还是被减去,因此,我们可以分别求出该情况下主武器和副武器的最大值,再相加,就是该种情况的最大值,维护出所有情况的最大值中的最大值即可。
可能你会有疑惑,因为我们在枚举种情况时,是分别求的两种武器的最大值,这样可能会由于我们假设是较大属性值的其实是该种情况下选中的两个武器属性中的较小值,导致其实这种选法并不属于这种情况。
如:主武器 s1=0 x1=100 副武器s2=0 x'1=10,当我们假设x1<x'1时,取得的主武器和副武器的最大值分别是-100和10,该种情况的最大值是-90,但是事实上100是大于10的。
不过其实这并不需要担心,假设出现了上面所说的情况,首先,该种情况下没有值比这个值更大,其次,这个值一定不是最后的答案。如果我们说上面所说情况是假设出错的话,那么在假设正确的情况下的最大值一定比这个值要大,因为|x-y|=max(x-y,y-x),所以该种情况不影响最后的答案。
因此,上述解法是正确的。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define For(i,a,b) for(int i=a;i<=b;i++)
const int N = 100010;
int t,n,m,k;
struct FastIO//输入挂,比原来的快读快了100ms
{
static const int S=200;
int wpos;
char wbuf[S];
FastIO():wpos(0){}
inline int xchar()
{
static char buf[S];
static int len=0,pos=0;
if(pos==len) pos=0,len=fread(buf,1,S,stdin);
if(pos==len) exit(0);
return buf[pos++];
}
inline int read()
{
int s=1,c=xchar(),x=0;
while(c<=32) c=xchar();
if(c=='-') s=-1,c=xchar();
for(;'0'<=c&&c<='9';c=xchar()) x=x*10+c-'0';
return x*s;
}
~FastIO()
{
if(wpos) fwrite(wbuf,1,wpos,stdout),wpos=0;
}
}io;
int s1[N],s2[N],x1[N][5],x2[N][5];
int main(){
t=io.read();
while(t--){
n=io.read(),m=io.read(),k=io.read();
For(i,1,n){
s1[i]=io.read();
For(j,0,k-1) x1[i][j]=io.read();
}
For(i,1,m){
s2[i]=io.read();
For(j,0,k-1) x2[i][j]=io.read();
}
int tot=1<<k;
ll tmp,maxx1=0,maxx2=0,ans=0;
For(i,1,tot){
For(j,1,n){
tmp=s1[j];
For(l,0,k-1){
if((1<<l)&i) tmp+=x1[j][l];
else tmp-=x1[j][l];
}
if(j==1) maxx1=tmp;
else maxx1=max(maxx1,tmp);
}
For(j,1,m){
tmp=s2[j];
For(l,0,k-1){
if((1<<l)&i) tmp-=x2[j][l];
else tmp+=x2[j][l];
}
if(j==1) maxx2=tmp;
else maxx2=max(maxx2,tmp);
}
ans=max(ans,maxx1+maxx2);
}
printf("%lld\n",ans);
}
return 0;
}