题解 - Birds

题目

题目大意

一条直线上有 \(n\) 棵树,第 \(i\) 棵树上有 \(c_i\)​ 只鸟。

在第 \(i\) 棵树下召唤一只鸟的魔力代价是 \(cost_i\)​。每召唤一只鸟,魔力上限会增加 \(B\)。每向前走一棵树,会增加 \(X\) 的魔力。一开始的魔力和魔力上限都是 \(W\)。你只能向前移动。

问最多能够召唤几只鸟。

思路简析

还是先考虑状态:必然不能以魔力为状态,那么只能以树和鸟,而答案却又是树和鸟所以我们需要反向思考一下:\(f_{i, j}\) 代表在第 \(i\) 棵树时总共已召唤了 \(j\) 只鸟时能有的最大魔力值,
最终结果是 \(\max\limits_{f_{n, j}\ is\ existent}\{j\}\)

转移方程:

\[f_{i, j} = \max\limits_{0 \leq k \leq \min\{j, c_i\}}\{f_{i-1, j-k}+X-cost_i\times k\} \]

\(Range: i_{1\rightarrow n}, j_{0\rightarrow\sum\limits_{p=0}^i c_p}\)

这里的 \(k\) 表示在第 \(i\) 棵树下召唤了 \(k\) 只鸟;加上的 \(X\) 是从第 \(i\) 棵树走到第 \(i+1\) 棵树的魔力值,所以严格来说其实当 \(i=n\) 时不应加上 \(X\),但是有判断条件即可;转入该方程应有条件:\(f_{i-1, j-k}-cost_i\times k\)(这里就是不加 \(X\))。

边界条件是 \(f_{0, 0} = W\)

那么就比较简单了。

这真的是背包 dp 吗?

另外考虑你的魔力上限,显然是 \(W+B\times j\)

我是真服了,\(cst_i \times k\) 会爆 int,硬控我 4h+。

完了到最后好像是被盾了。

这东西虽然是三层循环,但是似乎时间复杂度仅是 \(\Omega(n\cdot\sum\limits_{i=1}^nc_i)\)\(10^7\) 的(若算错请指正谢谢。)。

点击查看代码
#include <bits/stdc++.h>
#include <bits/extc++.h>
namespace {
using namespace std;
using namespace __gnu_pbds;
#define fiin(x) freopen(x".in", "r", stdin)
#define fiout(x) freopen(x".out", "w", stdout)
#define files(x) fiin(x), fiout(x)
#define und unsigned
#define ll long long
#define db double
#define pii pair<int, int>
#define mp(x, y) make_pair(x, y)
#define m1p(x, y) ((x<<14)+y)
#define fir first
#define sec second
#define hap gp_hash_table
// #define pri_que 
const int man = 1e3+10, mac = 1e4+10;
}

ll n, W, B, X;
ll c[man], cst[man], sum[man];
ll f[man][mac];
int main () {
    // files("test");
    scanf("%lld%lld%lld%lld", &n, &W, &B, &X);
    for (int i = 1; i <= n; ++ i) scanf("%lld", c+i), sum[i] = sum[i-1]+c[i];
    for (int i = 1; i <= n; ++ i) scanf("%lld", cst+i);
    memset(f, -1, sizeof(f)), f[0][0] = W;

    for (int i = 1; i <= n; ++ i) 
        for (int j = 0; j <= sum[i]; ++ j) {
            for (int k = 0; k <= min(1LL*j, c[i]); ++ k) 
                if (f[i-1][j-k]-cst[i]*k>=0) 
                    f[i][j] = max(f[i][j], f[i-1][j-k]+X-cst[i]*k);
            f[i][j] = min(f[i][j], W+B*j); }

    for (int i = sum[n]; i; -- i) 
        if (f[n][i] != -1) return printf("%d", i)&0;
        
    return puts("0")&0;
}

点名批评可爱洛天依,写 \(\max\) 不写范围,中间变量还来回标错。

posted @ 2024-11-23 19:12  STA_Morlin  阅读(18)  评论(0编辑  收藏  举报