题目描述
数据范围
题目分析
这一道题很容易就可以想到DP
因为它要求的是使
,所以我们便按照题目要求设一个DP
为已经定了前
个数,他们与
的乘积和为
的与
的乘积和的最大值
然后对于当前一个数,我们从
到
枚举,然后是转移方程:
初始化为
,答案为
(显然)
可我们发现这只能获得60分,因为空间和时间不允许,就让我们一一来解决
空间
这一个很好解决,直接开滚动数组即可
时间
我们发现,时间复杂度好像是两三亿,其实极限数据跑也不会超过1500ms,所以我们尝试着卡一下常数。
我们设
,
我们发现对于当前的
,如果这个
小于
或大于
,都是没有意义的(显然)
所以我们就这样处理一下,然后…AC!
一些题外话
听说这道题可以用单调队列做出来?(应该是正解)
代码
#include<cstdio>
#include<cstring>
using namespace std;
int a[210],b[210],c[210],d[210];
int f[2][210000];int min[210],max[210];
int mymax(int x,int y) {return x>y?x:y;}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
min[n+1]=max[n+1]=0;
for(int i=n;i>=1;i--) min[i]=min[i+1]+a[i]*c[i],max[i]=max[i+1]+b[i]*c[i];
memset(f,-60,sizeof(f));
int ze=mymax(0,max[1]);
f[0][ze]=0;int t=0;
for(int i=1;i<=n;i++){
t=1-t;
for(int j=ze-max[i+1];j<=ze-min[i+1];j++) f[t][j]=-999999999;
for(int j=a[i];j<=b[i];j++)
for(int k=ze-max[i+1];k<=ze-min[i+1];k++){
int g=f[1-t][k-j*c[i]]+j*d[i];
if(f[t][k]<g) f[t][k]=g;
}
}
printf("%d\n",f[t][ze]);
return 0;
}