CF994F Compute Power

题意

有一堆任务,每个计算机可以跑一或两个。第 i i i个任务需要消耗 a i a_i ai的能量,使用 b i b_i bi个核。你可以安排这些任务,安排在一个计算机上第二轮的任务的能量消耗必须比第一轮的小。问第一轮任务的能量总和除以核总数最小。

思路

看到能量除以总和最小,就想到01分数规划的问题。二分答案,对于这个答案跑DP检验是否可行。 a i ÷ b i ≤ x a_i\div b_i \le x ai÷bix 等价于 a i − b i ∗ x ≤ 0 a_i-b_i*x\le 0 aibix0 于是可以判断DP结果是否有小于0的状态来二分。
至于DP,因为放在第二轮的能量消耗必须要比第一轮的小,且第二轮可以不放,于是可以用 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示从大到小安排,安排到第 i i i个时,有 j j j个任务能量比 a i a_i ai大安排在了第一轮且还未被安排第二轮, k k k个任务能量跟 a i a_i ai相等安排在了第一轮且还未被安排第二轮的状态。

换句话说, f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]就是扫到 i i i,第二轮还可以安排 j j j个,有 k k k个跟 a i a_i ai相等的被安排在了第一轮时 ∑ i = 1 i ∈ { 第 一 轮 } a i − x ∗ ∑ i = 1 i ∈ { 第 一 轮 } b i \sum^{i\in\{第一轮\}}_{i=1}a_i-x*\sum^{i\in\{第一轮\}}_{i=1}b_i i=1i{}aixi=1i{}bi的最小值。

转移就是

if(a[i]<a[i-1]){//1
	f[i][j][0]=min(f[ i ][ j ][0],j-k+1>=0?f[i-1][j-k+1][k]:inf);
	f[i][j][1]=min(f[ i ][ j ][1],j-k>=0?f[i-1][j-k][k]+task[i].a-x*task[i].b:inf);
}else{//2
	f[i][j][k]=min(f[i-1][j+1][k],k-1>=0?f[i-1][j][k-1]+task[i].a-x*task[i].b:5e9);
}

意思就是:

  1. 如果 a i &lt; a i − 1 a_i&lt;a_{i-1} ai<ai1 ,那么跟 a i a_i ai相等且放在第一轮的状态只有 0 0 0 1 1 1,即 k ∈ { 0 , 1 } k\in\{0,1\} k{0,1},那么转移也就只有两种状态:
    1. i i i项任务安排在第二轮,此时第三维无疑是 0 0 0,那么 k k k就变为了枚举 i − 1 i-1 i1时有多少个任务与 a i − 1 a_{i-1} ai1相等且安排在了第一轮。这些任务明显大于 a i a_i ai,于是就用上一状态加上任务 i i i放在第二轮的贡献(无)更新答案。
    2. i i i项任务安排在第一轮,此时第三维是 1 1 1,那么 k k k也照样是枚举 i − 1 i-1 i1时有多少个任务与 a i − 1 a_{i-1} ai1相等且被安排在了第一轮。这些任务也是大于 k k k的,于是也是用上一轮的状态加上任务 i i i放在第一轮的贡献( a i − x ∗ b i a_i-x*b_i aixbi)更新答案。
    3. tips:
      1. 上一轮状态:因为枚举到的 k k k个任务比 a i a_i ai大了,所以现在枚举到的 j j j要减掉 k k k,然后再看当前(也就是第 i i i项)任务放第一轮还是第二轮.
      2. inf:把不可行的状态置成inf,使他不会更新之后的答案.
  2. 如果 a i = = a i − 1 a_i==a_{i-1} ai==ai1 ,那么便枚举当前 j j j和当前 k k k然后用当前任务放第一轮和第二轮的两种方案更新答案。

枚举 k k k的时候可以加点优化,但现在已经足够了。
然后最后扫一遍 f [ n ] [ j ] [ k ] f[n][j][k] f[n][j][k]看是不是有状态小于0;
有就可以达到更小的 k k k,反之。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef double db;
const int Mx=55;
db f[Mx][Mx][Mx];
struct Task{
    db a,b;
}task[Mx];
int n;
long long ans;
bool cmp(Task a,Task b){return a.a>b.a;}
bool judge(db x){
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=n+1;j++)
            for(int k=0;k<=n+1;k++)
                f[i][j][k]=5e9;
    f[0][0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i;j++)
            for(int k=0;k<=i;k++)
                if(task[i].a<task[i-1].a){
                    f[i][j][0]=min(f[i][j][0],j-k+1>=0?f[i-1][j-k+1][k]:5e9);
                    f[i][j][1]=min(f[i][j][1],j-k>=0?f[i-1][j-k][k]+task[i].a-x*task[i].b:5e9);
                }else{
                    f[i][j][k]=min(f[i-1][j+1][k],k-1>=0?f[i-1][j][k-1]+task[i].a-x*task[i].b:5e9);
                }
    for(int j=0;j<=n;j++)
        for(int k=0;k<=n-j;k++)
            if(f[n][j][k]<=0)return 1;
    return 0;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lf",&task[i].a);
    for(int i=1;i<=n;i++)scanf("%lf",&task[i].b);
    sort(task+1,task+1+n,cmp);
    task[0].a=-1e8;
    db l=0,r=5e9;
    for(int t=1;t<=100;t++){
        db mid=(l+r)/2;
        if(judge(mid))r=mid;
        else l=mid;
    }
    ans=ceil(l*1000);
    printf("%lld",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值