100044. abcd

题目描述

在这里插入图片描述

数据范围

N 200 , 25 a i , b i 25 , 1 c i 20 , 0 d i 1 0 5 N \le 200,-25 \le a_i,b_i \le 25,1 \le c_i \le 20,0 \le d_i \le 10^5

题目分析

这一道题很容易就可以想到DP
因为它要求的是使 i = 1 n e [ i ] c [ i ] = 0 ( a [ i ] e [ i ] b [ i ] ) \sum_{i=1}^{n}e[i]*c[i]=0(a[i] \le e[i] \le b[i]) ,所以我们便按照题目要求设一个DP
f [ i ] [ j ] f[i][j] 为已经定了前 i i 个数,他们与 c [ i ] c[i] 的乘积和为 j j 的与 d [ i ] d[i] 的乘积和的最大值
然后对于当前一个数,我们从 a [ i ] a[i] b [ i ] b[i] 枚举,然后是转移方程:
f [ i ] [ j ] = m a x ( f [ i 1 ] [ j k c [ i ] ] + k d [ i ] ) ( a [ i ] k b [ i ] ) f[i][j]=max(f[i-1][j-k*c[i]]+k*d[i])(a[i] \le k \le b[i])
初始化为 f [ 0 ] [ 0 ] = 0 f[0][0]=0 ,答案为 f [ n ] [ 0 ] f[n][0] (显然)
可我们发现这只能获得60分,因为空间和时间不允许,就让我们一一来解决

空间

这一个很好解决,直接开滚动数组即可

时间

我们发现,时间复杂度好像是两三亿,其实极限数据跑也不会超过1500ms,所以我们尝试着卡一下常数。
我们设 m a x [ i ] = j = i n b [ j ] c [ j ] max[i]=\sum_{j=i}^{n}b[j]*c[j] m i n [ i ] = j = i n a [ j ] c [ j ] min[i]=\sum_{j=i}^{n}a[j]*c[j]
我们发现对于当前的 f [ i ] [ j ] f[i][j] ,如果这个 j j 小于 m a x [ i + 1 ] -max[i+1] 或大于 m i n [ i + 1 ] -min[i+1] ,都是没有意义的(显然)
所以我们就这样处理一下,然后…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;
}
发布了58 篇原创文章 · 获赞 12 · 访问量 8568

猜你喜欢

转载自blog.csdn.net/fengqiyuka/article/details/85028637
今日推荐