codeforces(牛客网dp专题,排序)

链接:https://ac.nowcoder.com/acm/problem/21314
来源:牛客网

牛牛正在打一场CF
比赛时间为T分钟,有N道题,可以在比赛时间内的任意时间提交代码
第i道题的分数为maxPoints[i],题目的分数随着比赛的进行,每分钟减少pointsPerMinute[i]
这是一场比较dark的Cf,分数可能减成负数
已知第i道题需要花费 requiredTime[i] 的时间解决
请问最多可以得到多少分

输入描述:
第一行输入两个整数N,T (1 ≤ N ≤ 50, 1 ≤ T ≤ 100000)
第二行输入n个整数maxPoints[i]
第三行输入n个整数pointsPerMinute[i]
第四行输入n个整数requiredTime[i]
1 ≤ maxPoints[i],pointsPerMinute[i],requiredTime[i] ≤ 100000
输出描述:
输出一个整数
示例1
输入
复制
1 74
502
2
47
输出
复制
408
示例2
输入
复制
2 40000
100000 100000
1 100000
50000 30000
输出
复制
0
示例3
输入
复制
3 75
250 500 1000
2 4 8
25 25 25
输出
复制
1200
示例4
输入
复制
3 30
100 100 100000
1 1 100
15 15 30
输出
复制
97000
备注:
子任务1: n <= 10
子任务2: n <= 20
子任务3: 无限制
很明显的一道dp题目,但是这道题目起始dp是没办法dp的。首先这到题目特别像一个01背包的问题。但是每种物品的顺序不同,最终获得的份数又不同。那么应该怎么排序呢。我们假设现在有两件物品i和j,现在已经到达了时间t1,该怎么安排这两件物品呢?
假如先i后j,最终获得的分数为:point[i]-(t1+x)*min[i]+point[j]-(t1+x+y)*min[j]
假如先j后i,最终获得的分数为:point[j]-(t1+y)min[j]+point[i]-(t1+x+y)min[i]
(point[i]代表第i件物品的分数,min[i]代表着第i件物品每分钟降低的分数,x,y代表着解决这道题目需要的时间)
两下一作差,得到y
min[i]-x
min[j]。我们要最大化分数,所以我们要使这个差大于0。之后的问题就是01背包了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=51;
const int maxm=1e5+100;
struct node{
	ll point;
	ll mint;
	ll time;
	friend bool operator <(const node a,const node b)
	{
		return b.time*a.mint>a.time*b.mint;//如此排序
	}
}p[maxx];
ll dp[maxm]; //要开long long
int n,t;

int main()
{
	while(~scanf("%d%d",&n,&t))
	{
		for(int i=1;i<=n;i++) scanf("%lld",&p[i].point);
		for(int i=1;i<=n;i++) scanf("%lld",&p[i].mint);
		for(int i=1;i<=n;i++) scanf("%lld",&p[i].time);
		sort(p+1,p+1+n);
		memset(dp,0,sizeof(dp));
		ll _max=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=t;j>=p[i].time;j--)
			{
				dp[j]=max(dp[j],dp[j-p[i].time]+(p[i].point-(ll)(j)*(ll)p[i].mint));//这里相当于枚举这个问题解决的时间
				_max=max(_max,dp[j]);//不断的记录最大值。
			}
		}
		printf("%lld\n",_max);
	}
}

努力加油a啊,(o)/~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值