题意
有
n
n
门课程,每门课程都有它的快乐值 ,学分
Ci
C
i
。现在选择若干门课程(可不选),它们的舒适值的结果满足下式:
(∑imHxi)2−∑imHxi∑imCxi−(∑imCxi)2
(
∑
i
m
H
x
i
)
2
−
∑
i
m
H
x
i
∑
i
m
C
x
i
−
(
∑
i
m
C
x
i
)
2
其中
xi
x
i
表示选择的第
i
i
门课的编号。求舒适值最大是多少。
1≤Hi≤10000
1
≤
H
i
≤
10000
1≤Ci≤100
1
≤
C
i
≤
100
思路
首先令
H=∑imHxi,C=∑imCxi
H
=
∑
i
m
H
x
i
,
C
=
∑
i
m
C
x
i
,原式化简为
H2−HC−C2
H
2
−
H
C
−
C
2
。
首先课程可以不选,那么原式小于等于零的情况可以不用考虑,而若原式大于零,
H>C
H
>
C
是肯定的,再提取公因式得
H(H−C)−C2
H
(
H
−
C
)
−
C
2
可见
C
C
一定时, 值越大越有利,考虑到
Ci
C
i
较小,可以将其作为背包的费用,01背包求出这个费用下
H
H
<script type="math/tex" id="MathJax-Element-51">H</script> 的最大值,再循环枚举所有可能的费用,求出舒适值的最大值。这其实很想枚举式子中一个变量,求另一个变量,但这里采用了01背包预处理另一变量。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long LL;
using namespace std;
int dp[50003];
LL f(LL C,LL H){return H*H-H*C-C*C;}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,H[503],C[503],s=0;
LL ans=0;
memset(dp,-1,sizeof(dp));
dp[0]=0;
scanf("%d",&n);
FOR(i,1,n)
{
scanf("%d%d",&H[i],&C[i]);
s+=C[i];
}
FOR(i,1,n)
DOR(j,s,C[i])
if(~dp[j-C[i]])
dp[j]=max(dp[j],dp[j-C[i]]+H[i]);
FOR(i,0,s)if(~dp[i])ans=max(ans,f(i,dp[i]));
printf("%lld\n",ans);
}
return 0;
}