链接: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代表着解决这道题目需要的时间)
两下一作差,得到ymin[i]-xmin[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)/~