链接: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: 无限制
题解
假设有两个相邻的a,b信息。
选择第一个先做的总分为a.mx-a.re*a.po+ b1=b.mx-(a.re+b.re)*b.po;
选择第二个先做的总分为 b.mx-a.re*b.po+b2=a.mx-(a.re+b.re)*a.po;
所以性价比的排序方式就是
a.mx-a.re*a.po+ b1=b.mx-(a.re+b.re)b.po>b.mx-a.reb.po+b2=a.mx-(a.re+b.re)*a.po;
排序后就变成了01背包问题。
代码
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=50,M=1e5;
ll dp[N+10][M+10];
struct node
{
ll mx,po;
ll re;
}a[N+10];
bool cmp(node a,node b){
ll a1=a.re*a.po;
ll b1=(a.re+b.re)*b.po;
ll a2=b.re*b.po;
ll b2=(a.re+b.re)*a.po;
return a1+b1<a2+b2;
}
int main()
{
int n,t;
cin>>n>>t;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].mx);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].po);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].re);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
for(int j=t;j>=0;j--){
if(j-a[i].re>=0)
dp[i][j]=max(dp[i][j],dp[i-1][j-a[i].re]+(a[i].mx-a[i].po*j));
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
}
ll ans=0;
for(int i=0;i<=t;i++)
ans=max(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
}