题意
有
门课程,每门课程都有它的快乐值
,学分
。现在选择若干门课程(可不选),它们的舒适值的结果满足下式:
其中
表示选择的第
门课的编号。求舒适值最大是多少。
思路
首先令
,原式化简为
。
首先课程可以不选,那么原式小于等于零的情况可以不用考虑,而若原式大于零,
是肯定的,再提取公因式得
可见
一定时,
值越大越有利,考虑到
较小,可以将其作为背包的费用,01背包求出这个费用下
的最大值,再循环枚举所有可能的费用,求出舒适值的最大值。这其实很想枚举式子中一个变量,求另一个变量,但这里采用了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;
}