20221113_T2A_背包贪心

题意

Steve 的城堡正在被大量的怪物袭击。
共有 \(n\) 个怪物正在袭击城堡,第 \(i\) 个怪物的攻击力为 \(a_i\),防御力为 \(b_i\)。城内有 \(m\) 个怪物猎人,第 \(j\) 个怪物猎人的生命值为 \(h_j\)。猎人可以和怪物对战,当猎人和第 \(i\) 个怪物对战时,猎人需要消耗连续的 \(b_i\) 秒时间攻击怪物,这段时间怪物也会攻击猎人,使猎人每秒初减少 \(a_i\) 的生命值。一旦猎人的生命值小于或等于猎人就会死亡无法继续对战。若猎人未死亡,则 bi 秒之后该怪物即被猎人消灭。这些怪物有一个超能力:每当一个怪物被消灭后,其余的所有怪物的攻击力和防御力都会增加 \(d\)。由于请猎人作战的费用十分昂贵,Steve 打算请一个猎人消灭尽可能多的怪物。
当然,Steve 可以自由决定猎人以何顺序消灭哪些怪物。Steve 想知道,对于每一个猎人求出最多能消灭多少个怪物。

题解

赛时得分: 0/100/100

我们从小情况入手,假如说现在有两个怪物,我知道两个都要选择了,那么我应该用什么顺序选择?

不妨令两个怪物分别是 \(a_1,b_1\)\(a_2,b_2\)

反正肯定是一个要 \(+d\) 的吗,我们假设我们选择 \(a_1,b_1\) 在前,看看他要满足什么条件。

那么就是 \(a_1b_1+(a_2+d)\times(b_2+d) \leq a_2b_2+(a_1+d)\times(a_1+d)\)

移项 \((a_2+b_2)d \leq (a_1+a_2)d\)

我们发现我们一定会选择 \(a+b\) 大的东西在前面。

既然确定了选择顺序,我们排序之后做一个 \(\mathcal{O}(n^2)\) 的背包,然后询问的时候就用最后一个背包二分就好了。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
template <typename T>inline void read(T& t){t=0; register char ch=getchar(); register int fflag=1;while(!('0'<=ch&&ch<='9')) {if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args> inline void read(T& t, Args&... args) {read(t);read(args...);}
const int N = 3e3 + 10, inf = 0x3f3f3f3f;

struct Info {
    int x, y;
    bool operator < (const Info &info) const {
        return x + y > info.x + info.y;
    }
}a[N];
int n, m, d;
int dp[N][N], ne[N];
bool used[N];

signed main() {
    freopen("hunter.in", "r", stdin);
    freopen("hunter.out", "w", stdout);
    read(n, m, d);
    for(int i = 1; i <= n; ++i) read(a[i].x);
    for(int i = 1; i <= n; ++i) read(a[i].y);
    sort(a + 1, a + n + 1);
    memset(dp, 0x3f, sizeof(dp));
    dp[0][0] = 0;
    for(int i = 1; i <= n; ++i) {
        dp[i][0] = 0;
        for(int j = 1; j <= i; ++j) dp[i][j] = min(dp[i - 1][j - 1] + (a[i].x + (j - 1) * d) * (a[i].y + (j - 1) * d), dp[i - 1][j]);
    }
    for(int i = 1; i <= n; ++i) ne[i] = dp[n][i];
    for(int i = 1; i <= m; ++i) {
        int hp;
        read(hp);
        int l = 0, r = n;
        while(l < r) {
            int mid = l + r + 1 >> 1;
            if(ne[mid] >= hp) r = mid - 1;
            else l = mid;
        }
        printf("%d ", l);
    }
    return 0;
}
// 55 65
// 105 30
posted @ 2022-11-13 22:01  Mercury_City  阅读(63)  评论(0编辑  收藏  举报