[Codeforces 922E]Birds

Description

题库链接

一条直线上有 $n$ 棵树,每棵树上有 $c_i$ 只鸟,在一棵树底下召唤一只鸟的魔法代价是 $cost_i$ 每召唤一只鸟,魔法上限会增加 $B$ 。从一棵树走到另一棵树,会增加魔法 $X$ ,一开始的魔法和魔法上限都是 $W$ 。问最多能够召唤的鸟的个数。

$1\leq n\leq 1000,1\leq B,X,W\leq 10^9,1\leq \sum_{i=1}^n c_i\leq 10000$

Solution

容易想到记 $f_{i,j}$ 为第 $i$ 棵树时,召唤了 $j$ 只鸟,剩余魔法的最大值。

转移的话就是枚举 $j-c_i$ 范围内的上一棵树的最大值。

但这样复杂度似乎不太漂亮,考虑用单调队列优化,一个显然的“滑动窗口”模型。复杂度为 $O(n\sum c)$ 的。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1000, C = 10000;

long long f[N+5][C+5], n, w, b, x, c[N+5], cost[N+5], tolc;
int q[C+5], head, tail; bool v[N+5][C+5];

void work() {
    scanf("%I64d%I64d%I64d%I64d", &n, &w, &b, &x);
    for (int i = 1; i <= n; i++) scanf("%I64d", &c[i]), tolc += c[i];
    for (int i = 1; i <= n; i++) scanf("%I64d", &cost[i]);
    f[0][0] = w; v[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= tolc; j++) f[i-1][j] = min(f[i-1][j]+x, w+b*j);
        head = tail = 0;
        for (int j = 0; j <= tolc; j++) {
            if (v[i-1][j]) {
                while (head < tail && f[i-1][q[tail-1]]+cost[i]*q[tail-1] <= f[i-1][j]+cost[i]*j) --tail;
                q[tail++] = j;
            }
            while (head < tail && j-q[head] > c[i]) ++head;
            if (head < tail && f[i-1][q[head]]+cost[i]*q[head]-cost[i]*j >= 0)
                f[i][j] = f[i-1][q[head]]+cost[i]*q[head]-cost[i]*j, v[i][j] = 1;
        }
    }
    int ans = 0;
    for (int i = 0; i <= tolc; i++) if (v[n][i]) ans = i;
    printf("%d\n", ans);
}
int main() {work(); return 0; }
posted @ 2018-03-31 14:44  NaVi_Awson  阅读(231)  评论(0编辑  收藏  举报