qduoj codeforces 山东省第八届acm省赛K题 CF (排序+01背包)

题目链接:https://qduoj.com/problem/133/点击打开链接

Problem Description

LYD loves codeforces since there are many Russian contests. In an contest lasting for T minutes there are n problems, and for theith problem you can get aiditi points, where ai indicates the initial points, di indicates the points decreased per minute (count from the beginning of the contest), and ti stands for the passed minutes when you solved the problem (count from the begining of the contest).
Now you know LYD can solve the ith problem in ci minutes. He can't perform as a multi-core processor, so he can think of only one problem at a moment. Can you help him get as many points as he can?

Input

The first line contains two integers n,T(0≤n≤2000,0≤T≤5000).
The second line contains n integers a1,a2,..,an(0<ai≤6000).
The third line contains n integers d1,d2,..,dn(0<di≤50).
The forth line contains n integers c1,c2,..,cn(0<ci≤400).

Output

Output an integer in a single line, indicating the maximum points LYD can get.

Example Input
3 10
100 200 250
5 6 7
2 4 10
Example Output
254

打过应该都知道比赛机制吧 题意很好理解

关键说说本题排序的问题和为什么要排序

一开始看到题有贪心取背包的感觉 问题是怎么贪心

如果单纯判断一个变量 比如每道题中该题每分钟掉分的分数 或者只考虑时间 都会因为另一个因素影响而到不到最优

取两道题的例子研究 

设第一题的分数为v1  每分钟掉d1  需要t1分钟

设第二题的分数为v2  每分钟掉d2  需要t2分钟

先1后2的得到分数的情况是:sum1=( v1 - d1 * t1 ) + ( v2 - d2 * ( t2 + t1 ) )

先2后1的得到分数的情况是:sum2=( v2 - d2 * t2 ) + ( v1 - d1 * ( t1 + t2 ) )

另dif=sum1-sum2  自己纸上算一算 得到式子dif = d1 * t2 - d2 * t1

当dif > 0 即sum1>sum2 即 先取1所得到的分数大于先取2所得到的分数的时候 就应该满足 d1 * t2 > d2 * t1  (dif = d1 * t2 - d2 * t1 > 0推出来的) 变换得到d1 / t1 > d2 / t2

由于博主语文不大好 比较难用文字表达出容易让人理解的意思 。。各位自行感受上一行最后一个表达式的含义

虽然不能理解意思 但是可以得到这样一个结论:当d1 / t1 > d2 / t2时 先取1后取2更优

那么能够推出的结论就是 对于任意第i道题 di / ti值越大 就需要越先解决这道题

很明显了 通过额外记录一个judge=di / ti 对judge从大到小排序 然后进行01背包的动态规划

#include <iostream>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <limits>
#include <string>
#include <string.h>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#define maxn 100010
using namespace std;
struct xjy
{
    int weight;
    int total;
    int decrese;
    double judge;
    bool operator < (const xjy &r)const
    {
        return judge<r.judge;
    }
};
xjy a[2222];
int dp[maxn];
int main()
{
    memset(dp,0,sizeof(dp));
    int n,t;
    scanf("%d%d",&n,&t);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i].total);
    }
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i].decrese);
    }
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i].weight);
    }
    for(int i=0;i<n;i++)
    {
        a[i].judge=(a[i].weight*1.0)/a[i].decrese;
    }
    sort(a,a+n);
    int ans=0;
    for(int i=0;i<n;i++)
        for(int j=t;j>=a[i].weight;j--)
        {
            dp[j]=max(dp[j],dp[j-a[i].weight]+a[i].total-a[i].decrese*j);
            ans=max(ans,dp[j]);
        }
    cout << ans << endl;
    return 0;
}





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值