动态规划-皮皮夏的奇怪比赛

Description

皮皮夏正在进行一场信息学的比赛,比赛时间为T分钟,一共有有N道题,可以在比赛时间内的任意时间提交代码。第i道题的分数为a[i],题目的分数随着比赛的进行,每分钟减少b[i],这场比赛非同一般,分数可能减成负数QAQ。

已知第i道题需要花费Time[i] 的时间解决,请问皮皮夏最多可以得到多少分?

Input

第一行输入两个整数N,T (1≤N ≤50,1≤T≤100000)

第二行输入n个整数a[i]

第三行输入n个整数b[i]

第四行输入n个整数Time[i]

1 ≤a[i],b[i],Time[i] ≤ 100000

Output

输出一个整数,表示皮皮夏最多可以得到的分数。

Sample Input 1 

1 74
502
2
47

Sample Output 1

408

Sample Input 2 

2 40000
100000 100000
1 100000
50000 30000

Sample Output 2

0

Sample Input 3 

3 75
250 500 1000
2 4 8
25 25 25

Sample Output 3

1200

Sample Input 4 

3 30
100 100 100000
1 1 100
15 15 30

Sample Output 4

97000

分析:有第i题和第j两题,先做哪道题呢?数学推导一下。

f(i,j)=ai-bi*ti+aj-bj*(ti+tj)=ai+aj-bi*ti-bj*tj-bj*ti

f(j,i)=aj-bj*tj+ai-ti*(ti+tj)=ai+aj-bi*ti-bj*tj-bi*tj

f(i,j)-f(j,i)=bi*tj-bj*ti>0  则 bi/ti  >  bj/tj

令key=bi / ti 对这些题目按照这个key从大到小排序,再进行01背包即可 下面是代码。

#include<iostream>
#include<algorithm>
using namespace std;
int f[100010];

struct ti{
    int a,b,time;
    double key;
}t[100010];

bool cmp(ti a,ti b){
    return a.key>b.key;
}

int main(){
    int n,T;
    cin>>n>>T;
    for(int i=1;i<=n;i++){
        cin>>t[i].a;
    }
    for(int i=1;i<=n;i++){
        cin>>t[i].b;
    }
    for(int i=1;i<=n;i++){
        cin>>t[i].time;
    }
    for(int i=1;i<=n;i++){
        t[i].key=t[i].b*1.0/t[i].time;
    }
    sort(t+1,t+1+n,cmp);
    for(int i=1;i<=n;i++){
        for(int j=T;j>=t[i].time;j--)
            f[j]=max(f[j],f[j-t[i].time]+t[i].a-t[i].b*j);
    }
    int ans=0;
    for(int i=1;i<=T;i++){
        ans=max(ans,f[i]);
    }
    cout<<ans;
    return 0;
}
 

优化:

#include<iostream>
#include<algorithm>
using namespace std;
int f[100010];

struct ti{
    int a,b,time;
    double key;
}t[100010];

bool cmp(ti a,ti b){
    return a.key>b.key;
}

int main(){
    int n,T;
    cin>>n>>T;
    for(int i=1;i<=n;i++){
        cin>>t[i].a;
    }
    for(int i=1;i<=n;i++){
        cin>>t[i].b;
    }
    for(int i=1;i<=n;i++){
        cin>>t[i].time;
    }
    for(int i=1;i<=n;i++){
        t[i].key=t[i].b*1.0/t[i].time;
    }
    sort(t+1,t+1+n,cmp);
    for(int i=1;i<=n;i++){
        for(int j=T;j>=t[i].time;j--)
            f[j]=max(f[j],f[j-t[i].time]+t[i].a-t[i].b*j);
    }
    int ans=0;
    for(int i=1;i<=T;i++){
        ans=max(ans,f[i]);
    }
    cout<<ans;
    return 0;
}
 

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值