怪物猎人[贪心+dp]

15 篇文章 0 订阅

在这里插入图片描述在这里插入图片描述


S o l u t i o n \mathcal{Solution} Solution

设当前砍到了第 2 2 2 个怪物,
代价 ( a i + d ) ( b i + d ) = a i b i + a i d + d b i + d 2 = a i b i + d ( a i + b i ) + d 2 (a_i+d)(b_i+d)=a_i b_i + a_i d + db_i+d^2=a_ib_i+d(a_i+b_i)+d^2 (ai+d)(bi+d)=aibi+aid+dbi+d2=aibi+d(ai+bi)+d2
发现只有 d ( a i + b i ) d(a_i+b_i) d(ai+bi) 是会变的量, 基于 贪心 思路, 使 ( a i + b i ) (a_i+b_i) (ai+bi) d d d 比较大时尽量小 .

于是按照 a i + b i a_i+b_i ai+bi 从大到小排序         ( 第 一 步 ) \ \ \ \ \ \ \ (第一步)        ()

光排序还不够, 还需要进行简单的 d p dp dp,
d p [ i , j ] 表 示 前 i 个 砍 j 个 所 需 要 的 最 小 代 价 dp[i, j] 表示前 i个砍j个所需要的最小代价 dp[i,j]ij
d p [ i , j ] = d p [ i − 1 , j − 1 ] + [ a i + ( i − 1 ) d ] ∗ [ b i + ( i − 1 ) d ] dp[i,j]=dp[i-1, j-1]+[a_i+(i-1)d]*[b_i+(i-1)d] dp[i,j]=dp[i1,j1]+[ai+(i1)d][bi+(i1)d]
得到 d p [ N , 1... N ] dp[N, 1...N] dp[N,1...N]二分查找 即可


C o d e \mathcal{Code} Code

#include<bits/stdc++.h>
#define reg register

typedef long long ll;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

ll read_l(){
        char c;
        ll s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 3005;

int N;
int M;
int D;

ll dp[maxn][maxn];

struct Node{ int a, b; } A[maxn];

bool cmp(Node x, Node y){ return x.a+x.b > y.a+y.b; }

int main(){
        freopen("hunter.in", "r", stdin);
        freopen("hunter.out", "w", stdout);
        N = read();
        M = read();
        D = read();
        for(reg int i = 1; i <= N; i ++) A[i].a = read();
        for(reg int i = 1; i <= N; i ++) A[i].b = read();
        std::sort(A+1, A+N+1, cmp);
        memset(dp, 0x3f, sizeof dp);
        for(reg int i = 0; i <= N; i ++) dp[i][0] = 0;
        for(reg int i = 1; i <= N; i ++)
                for(reg int j = 1; j <= i; j ++)
                        dp[i][j] = std::min(dp[i-1][j], dp[i-1][j-1] + 1ll*(A[i].a+1ll*D*(j-1))*(A[i].b+1ll*D*(j-1)));
        for(reg int i = 1; i <= M; i ++)
                printf("%d ", std::lower_bound(dp[N]+1, dp[N]+N+1, read_l())-dp[N]-1);
        return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值