题目大意
在玩CSGO的你有 n n 把枪和个弹匣,每把枪有一个威力 Smi S m i ,每个弹匣也有一个威力 Ssi S s i ,但是由于这个游戏神(che)奇(dan)的设定,所以枪和弹匣可能会出现一些奇妙的效果来增强威力,具体来说,每把枪和每个弹匣都有 k k 个参数性,而一把枪和一个弹匣组合的战斗值为 Smi+Ssi+∑ki=1|xm[i]−xs[i]| S m i + S s i + ∑ i = 1 k | x m [ i ] − x s [ i ] | ,求你能组合出的最大战斗值。
解题报告
我居然又忘了如何对付绝对值的套路……
首先由于绝对值非负,所以 |x−y|=max(x−y,y−x) | x − y | = m a x ( x − y , y − x )
由于我们在求最大值,所以较小的那个值不仅不合法,而且肯定不是最优。这样的话可以将 |x−y| | x − y | 分为两类
x x 与 和 −x − x 与 y y 。然后将x,y分别加入两个属性内,这样就可以直接找出最大值,而不用枚举。
但以上都是 k=1 k = 1 的情况,如果 k>1 k > 1 的话,只需要 2k 2 k 枚举每个参数是正还是负,再求最大值就行了。
示例代码
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
int tst,n,m,k,a[100005][10],b[100005][10];
LL ans;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void readi(int &x){
x=0; char ch=nc(),lst='+';
while ('0'>ch||ch>'9') {lst=ch; ch=nc();}
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
if (lst=='-') x=-x;
}
int main()
{
freopen("csgo.in","r",stdin);
freopen("csgo.out","w",stdout);
readi(tst);
while (tst--){
readi(n); readi(m); readi(k); ans=0;
for (int i=1;i<=n;i++)
for (int j=0;j<=k;j++) readi(a[i][j]);
for (int i=1;i<=m;i++)
for (int j=0;j<=k;j++) readi(b[i][j]);
for (int s=0;s<(1<<k);s++){
LL Maxa=-(9e18),Maxb=-(9e18),tem;
for (int i=1;i<=n;i++){
tem=a[i][0];
for (int j=1;j<=k;j++) if (s&(1<<(j-1))) tem+=a[i][j]; else tem-=a[i][j];
Maxa=max(Maxa,tem);
}
for (int i=1;i<=m;i++){
tem=b[i][0];
for (int j=1;j<=k;j++) if (s&(1<<(j-1))) tem-=b[i][j]; else tem+=b[i][j];
Maxb=max(Maxb,tem);
}
ans=max(ans,Maxa+Maxb);
}
printf("%lld\n",ans);
}
return 0;
}