链接:
CSGO: http://acm.hdu.edu.cn/showproblem.php?pid=6435
题意:
有A和B两种武器,每个武器本身有价值S和k个不同属性x[1],x[2]…x[k]
现给出n件A和m件B的信息,要求从中找出一个A和一个B使得下图值最大
数据规模:
T<=100, n<=100000, m<=100000, K<=5, 0<=S<=1e9, |x[i]|<=1e9, sum of (n+m)<=300000
思路:
一开始没看到绝对值符号,觉得Σ(xa[i]-xb[i]) = Σxa[i] - Σxb[i]乱写一发果断WA
这个问题的突破口其实在K的大小,K <= 5,把Σ| xa[i] - xb[i] |展开应该有许多的+,-号,且xa[i]前的+号 == xb[i]前的-号,反之亦然。可以通过枚举xa[i]前面的符号可能情况,比如:
+xa[1]+xa[2]-xa[3]-xa[4]+xa[5]
对应符号互补的xb[i]的对应方案:
-xb[1]-xb[2]+xb[3]+xb[4]-xb[5]
这样的话,对每一件装备,可能产生2^k种总属性值[S+X,(X = Σ±x[i],X有2^k种)],最终2^k种方案里最大属性值记录下来,当作这种符号分配方案能产生的最大的值。两种装备(A/B)符号互补的分配方案对应的最大属性值加和起来即为最终答案。
标程:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int T,n,m,K,val,x[6];
LL A[64],B[64],Ans;
int main()
{
int i,k,S;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&n,&m,&K);
Ans=0;
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
for (i=1;i<=n;i++)
{
scanf("%d",&val);
for (k=0;k<K;k++)
scanf("%d",&x[k]);
for (S=0;S<1<<K;S++)
{
LL Sum=val;
for (k=0;k<K;k++)
Sum+=x[k]*((((S>>k)&1)<<1)-1);
A[S]=max(A[S],Sum);
}
}
for (i=1;i<=m;i++)
{
scanf("%d",&val);
for (k=0;k<K;k++)
scanf("%d",&x[k]);
for (S=0;S<1<<K;S++)
{
LL Sum=val;
for (k=0;k<K;k++)
Sum+=x[k]*((((S>>k)&1)<<1)-1);
B[S]=max(B[S],Sum);
}
}
for (S=0;S<1<<K;S++)
Ans=max(Ans,A[S]+B[(1<<K)-1-S]);
printf("%lld\n",Ans);
}
}
自写代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int p1[100010][6],p2[100010][6];
ll maa[65],mia[65],mab[65],mib[65];
inline void gmax(ll &a,ll b){
if(a < b)a = b;
}
inline void gmin(ll &a,ll b){
if(a > b)a = b;
}
int main(){
int T,n,m,k;
scanf("%d",&T);
while(T--){
ll ans = -INF;
scanf("%d%d%d",&n,&m,&k);
for(int i = 0;i < n;i++)
for(int j = 0;j <= k;j++)
scanf("%d",&p1[i][j]);
for(int i = 0;i < m;i++)
for(int j = 0;j <= k;j++){
scanf("%d",&p2[i][j]);
if(!j)p2[i][j]*=-1;
}
fill(maa,maa + sizeof(maa)/sizeof(ll),-INF);
fill(mab,mab + sizeof(mab)/sizeof(ll),-INF);
fill(mia,mia + sizeof(mia)/sizeof(ll),INF);
fill(mib,mib + sizeof(mib)/sizeof(ll),INF);
for(int i = 0;i < n;i++)
for(int j = 0;j < 2<<k;j++){
ll sum = 0;
for(int t = 0;t <= k;t++)
if(j & (1<<t))sum += p1[i][t];
else sum -= p1[i][t];
gmax(maa[j],sum);
gmin(mia[j],sum);
}
for(int i = 0;i < m;i++)
for(int j = 0;j < 2<<k;j++){
ll sum = 0;
for(int t = 0;t <= k;t++)
if(j & (1<<t))sum += p2[i][t];
else sum -= p2[i][t];
gmax(mab[j],sum);
gmin(mib[j],sum);
}
for(int i = 0;i < 2<<k;i++)
gmax(ans,maa[i] - mib[i]),gmax(ans,mab[i] - mia[i]);
printf("%lld\n",ans);
}
return 0;
}