得分(dp)

题目描述
现在 zql手上有 N 道题,他总共有 T 的时间来完成他们中的一些或全部。每道题有一个完成所需时间 t[i]和一个难度系数 c[i]。如果 zql 在剩余 x 个单位时间的时候开始做题i,并且能够完成,那么总分加上 x*c[i]。现在 zql 要从这 N 道题中选出一些在T个单位时间内完成,并且按照某种顺序依次完成它们(zql 每个单位时间只能做一道题,并且一旦他决定做某题就会一直做直到做完),那么他最多能够拿到多少分呢?

输入
总共包括 N+1 行
第一行,两个用空格隔开的正整数 N 和 T,分别表示题目总数和总时间。
第 2 到 N+1 行,每行包含两个正整数,第 i+1 行的两个正整数分别表示 t[i]和 c[i].

输出
共包括 1 行。 一行一个整数,表示最大能够得到的分数。

样例输入
【样例1】
3 10
2 1
8 9
2 5
【样例2】
3 12
3 6
7 5
4 2

样例输出
【样例1】
122
【样例2】
117

提示
样例1解释:最优方案为在剩余 10 个单位时间的时候开始做第 3 题(需要 2 个单位时间),剩余 8 个单位时间的时候开始做第 2 题(需要 8 个单位时间),总得 分为 10×5+(10-2)×9=122。

对于20%的数据,N≤8,T≤200。
对于60%的数据,N≤15,T≤1000。
对于90%的数据,N≤2000且满足T不小于做完N道题所需时间的总和。
对于100%的数据,N≤3000,T≤10000,所有ti和ci均不超过100。保证答案在 32 位有符号整型范围内。

思路
根据x[i]*t[j]得出每两个问题的所占权值差,并排序,DP直接推解即可

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=3005;
const int M=10005;
const int INF=0x3f3f3f;
const ull sed=31;
const ll mod=1e9+7;
const double eps=1e-8;
const double PI=acos(-1.0);
typedef pair<int,int>P;
 
struct node
{
    ll c,t;
}qus[N];
ll dp[M];
int n,T;
 
bool cmp(node a,node b)
{
    return a.c*b.t>a.t*b.c;
}
int main()
{
    scanf("%d%d",&n,&T);
    for(int i=0;i<n;i++) scanf("%lld%lld",&qus[i].t,&qus[i].c);
    sort(qus,qus+n,cmp);
    for(int i=0;i<n;i++)
    {
        for(int j=T;j>=qus[i].t;j--)
        {
            dp[j]=max(dp[j],dp[j-qus[i].t]+(T-j+qus[i].t)*qus[i].c);
        }
    }
    ll ans=0;
    for(int i=0;i<=T;i++) ans=max(ans,dp[i]);
    printf("%lld\n",ans);
    return 0;
}
发布了235 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43935894/article/details/104199655