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;
}