Problem J. CSGO
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 683 Accepted Submission(s): 353
题目链接
Problem Description
You are playing CSGO.
There are n Main Weapons and m Secondary Weapons in CSGO. You can only choose one Main Weapon and one Secondary Weapon. For each weapon, it has a composite score S.
The higher the composite score of the weapon is, the better for you.
Also each weapon has K performance evaluations x[1], x[2], …, x[K].(range, firing rate, recoil, weight…)
So you shold consider the cooperation of your weapons, you want two weapons that have big difference in each performance, for example, AWP + CZ75 is a good choose, and so do AK47 + Desert Eagle.
All in all, you will evaluate your weapons by this formula.(MW for Main Weapon and SW for Secondary Weapon)
Now you have to choose your best Main Weapon & Secondary Weapon and output the maximum evaluation.
Input
Multiple query.
On the first line, there is a positive integer T, which describe the number of data. Next there are T groups of data.
for each group, the first line have three positive integers n, m, K.
then, the next n line will describe n Main Weapons, K+1 integers each line S, x[1], x[2], …, x[K]
then, the next m line will describe m Secondary Weapons, K+1 integers each line S, x[1], x[2], …, x[K]
There is a blank line before each groups of data.
T<=100, n<=100000, m<=100000, K<=5, 0<=S<=1e9, |x[i]|<=1e9, sum of (n+m)<=300000
Output
Your output should include T lines, for each line, output the maximum evaluation for the corresponding datum.
Sample Input
2
2 2 1
0 233
0 666
0 123
0 456
2 2 1
100 0
1000 100
1000 100
100 0
Sample Output
543
2000
题意:
给你n个主武器,m个副武器,每个武器上有k个属性
下面n行表示n个主武器,每行K+1个数字,第一个表示该武器的分数s,然后是K个属性x[1]...x[k]
下面m行同理
要你选一把主武器和一把副武器,使得他们总的分数最大,总的分数的公式就是
解析:
首先一开始做的时候,看到这个K<=5,我就想枚举的符号,
每一位只有两种可能,总共有2^5种
然后我的做法是把每一个武器的状态打表记录,Mw[i][j]表示在状态i时,第j把主武器的值
(i表示的二进制,对应位为0表示改位为-,否则为+)
这里因为S无论如何都是+的,所以我们不需要管他,只要Mw[][j]都加上
同理Sw[i][j]也打表预处理出来。
然后我就是在每一个状态i下(c=i的各位都取反),求
MAX(max(Mw[i][1..n])+max(Sw[c][1..m]),max(Mw[c][1..n])+max(Sw[i][1..m]))
最后求出来的就是答案了。
然后这样做为什么是正确的?我在写代码之前也想了很久,但是想不出来就直接莽着交了一发,发现过了。
后来队友提供了一种思路。
在我这种做法求出来的值,一定是每次的最大值,即使他对于当前是非法的情况
譬如n=2,m=2,k=2
mw1: 0 20 2 mw2:0 200000 199998
sw1:0 100000 3 sw2:0 21 300000
对于10状态时,mw的状态是10,sw的状态是01
那么mw的最大值是mw1(18) sw的最大值是sw2(299979)
但是我们发现对于10这个状态,mw1和sw2的组合是非法的。因为21>20,但是我们把这种答案作为10状态的最大值了
那么如果最后求出来最大值是非法的情况该怎么办?
那么首先我们就应该了解到上述那个公式的性质——对于非法的情况,合法的情况一定是最大的。
即曼哈顿距离是两个数最大的距离。譬如mw:5 3 sw:7 1
7-5+1-3=0
7-5+3-1=4
5-7+1-3=-4
5-7+3-1=0
我们可以发现对于上面的情况|7-5|+|3-1|是最大的情况。
证明也很简单,对于5 3 7 1,如果你不按对应大小顺序进行分配符号,
那么两对里面一定有是负的,所以最大的情况一定是两对的结果都是正的情况,
那么就是他们相减后的绝对值相加。
那么明白这个性质后,其实结论就很显而易见了。
题目所求的答案就是所有曼哈顿距离里面的最大值,而曼哈顿距离又是所有情况(非法/合法)下的最大值
假定有一个非法的情况>合法的最大值,那么我们一定可以通过把非法的情况的正负号改变,
使他变成合法的情况,又合法的情况的值一定又是大于非法的情况的值,所以最后还是答案一定是一个合法的情况。
然后我那种方法一定是可以枚举出最大值的,然后最大值一定又是合法的情况(即使中间枚举不同状态时,有一些非法的最大值,但这些值最后一定是小于最后合法的最大值的),所以这种方法是可以的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Min(a,b) (a<=b?a:b)
using namespace std;
typedef long long ll;
const int MAX = 1<<5;
const int MAXN = 1e5+10;
ll Mw[MAX][MAXN],Sw[MAX][MAXN];
int main()
{
int t;
int n,m,K;
//read(t);
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&K);
int N = 1<<(K);
for(int i=0;i<N;i++)
{
for(int j=1;j<=n;j++) Mw[i][j]=0;
for(int j=1;j<=m;j++) Sw[i][j]=0;
}
for(int i=1;i<=n;i++)
{
int tmp;
scanf("%d",&tmp);
for(int j=0;j<N;j++) Mw[j][i]+=tmp;
for(int j=1;j<=K;j++)
{
scanf("%d",&tmp);
for(int w=0;w<N;w++)
{
if((w&(1<<(j-1)))==0)
{
Mw[w][i]-=tmp;
}
else
{
Mw[w][i]+=tmp;
}
}
}
}
for(int i=0;i<N;i++)
{
sort(Mw[i]+1,Mw[i]+1+n);
}
for(int i=1;i<=m;i++)
{
int tmp;
scanf("%d",&tmp);
for(int j=0;j<N;j++) Sw[j][i]+=tmp;
for(int j=1;j<=K;j++)
{
scanf("%d",&tmp);
for(int w=0;w<N;w++)
{
if((w&(1<<(j-1)))==0)
{
Sw[w][i]-=tmp;
}
else
{
Sw[w][i]+=tmp;
}
}
}
}
for(int i=0;i<N;i++)
{
sort(Sw[i]+1,Sw[i]+1+m);
}
ll ans=0;
for(int i=0;i<N;i++)
{
int oth=i^(N-1);
ans=max(Sw[i][m]+Mw[oth][n],ans);
ans=max(Sw[oth][m]+Mw[i][n],ans);
}
printf("%lld\n",ans);
}
return 0;
}