题意

\(m\)个大佬,第\(i\)个大佬的自信值为\(C_i\)。每次怼大佬之前,你的自信值为\(mc\),等级\(L=0\),嘲讽值 \(F=1\) 。对于每一个大佬,都有\(n\)天时间,第\(i\)天你将会被大佬打击,自信值下降\(a_i\)。如果在某一天你的自信值为负数,那么你失败了

每一天你可以进行以下操作的任意一个:

  1. 还一句嘴,使大佬自信值下降\(1\)

  2. 刷水题,使自己的自信值增加\(w_i\)

  3. 把自己的等级\(+1\)

  4. 把自己的\(F\)乘上\(L\)

  5. 怼大佬,使得大佬的自信值下降 \(F\),之后 \(L = 0,F = 1\)。这个操作可以进行 \(k=\{0,1,2\}\)

你必须在某一天使大佬的自信值恰好为 \(0\) 。如果大佬的自信值为负,则判定你失败

对于每个大佬,请判断你是否成功


解法

可以发现胜利的必要条件是自己能在大佬被怼死之前存活下来

我们设一个DP \(f[i][j]\) 为在第 \(i\) 天,剩余自信值为 \(j\) 时最多能够把多少天用来怼大佬

在该数组中取一个最大值即可求出最多能有多少天用于怼大佬,把这个天数设置为 \(D\)

可以发现怼大佬这一操作的威力只与操作 \(4,5\) 有关

一遍 BFS 求出所有的二元组 \(<D, F>\) 代表花 \(D\) 天可以对大佬造成的伤害 \(F\)

贪心的思考,对于某一个 \(F\) ,我们只需要保留最小的 \(D\) 即可,这样可以减少很多状态

你能怼死大佬有三种情况:

  1. 不怼大佬,只还嘴。满足 \(C_i \leq D\) 即可

  2. 只怼一次大佬。这时能怼死大佬需要满足存在一个二元组 \((d',f')\)使得 \(f'\leq C_i\) 并且 \(f'+D-d' \ge C_i\)。(即怼不死的部分用还嘴耗掉)

  3. 怼两次大佬。可以发现,当 \(f_1 +f_2 \leq C_i\) 并且 \(f_1+f_2+(D-d_1-d_2)\geq C_i\) 时可以将大佬怼死。我们把所有二元组按 \(f\) 排序,第一个条件用 two_pointers 维护(对于某个 \(f\) ,能与它配对的二元组是一个连续的区间),至于第二个,我们把第二个指针视作必选的二元组,那么只需要在它可以配对的区间中选一个 \(f-d\) 最大的即可


代码

#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 210;
const int MAX_S = 1e6 + 10;

#define Pii pair<int, int>
#define mp make_pair
#define x first
#define y second

int read();

int N, Q, Hp, K;
int T, mxc, top;

int b[MAX_N], h[MAX_N], p[MAX_N];
int f[MAX_N][MAX_N * 10];

struct sta { int i, F, L; };

queue<sta> que;
Pii a[6 * MAX_S], c[MAX_S];

struct Hash_Table {
#define mod 4194303

    int cap;
    int head[mod + 10];
    int nxt[mod + 10], a[mod + 10], b[mod + 10];

    Hash_Table() : cap(0) {}

    int Hash(Pii pr) {
        int x = pr.x, y = pr.y;
        return (1LL * x * 20030207 + y) & mod;
    }
    void insert(Pii pr) {
        int u = Hash(pr);
        nxt[++cap] = head[u];
        head[u] = cap;
        a[cap] = pr.x, b[cap] = pr.y;
    }
    int count(Pii pr) {
        int u = Hash(pr);
        for (int i = head[u]; i; i = nxt[i])
            if (a[i] == pr.x && b[i] == pr.y)  return 1;
        return 0;
    }
#undef mod
} Map;

inline void chkmax(int& x, int y) { x = x > y ? x : y; }

void init() {
    for (int i = 1; i <= N; ++i)
        for (int j = b[i]; j <= Hp; ++j) {
            chkmax(f[i][j - b[i]], f[i - 1][j] + 1),
            chkmax(f[i][min(j - b[i] + h[i], Hp)], f[i - 1][j]);
        }
    for (int i = 1; i <= N; ++i)
        for (int j = 0; j <= Hp; ++j)  chkmax(T, f[i][j]);
}

void BFS() {
    que.push((sta){1, 1, 0});
    while (!que.empty()) {
        sta fr = que.front(); que.pop();
        int I = fr.i, F = fr.F, L = fr.L;
        if (I >= T)  continue;
        que.push((sta){I + 1, F, L + 1});
        if (L > 1 && 1LL * L * F <= mxc && !Map.count(mp(1LL * L * F, I + 1))) {
            a[++top] = mp(L * F, I + 1);
            que.push((sta){I + 1, L * F, L});
            Map.insert(a[top]);
        }
    }
    int tp = 0;
    sort(a + 1, a + top + 1);
    for (int i = 1; i <= top; ++i)
        if (a[i].x ^ a[i - 1].x)  c[++tp] = a[i];
    top = tp;
}

int main() {

    N = read(), Hp = read(), K = read();
    for (int i = 1; i <= N; ++i)  b[i] = read();
    for (int i = 1; i <= N; ++i)  h[i] = read();

    Q = read();
    for (int i = 1; i <= Q; ++i)  p[i] = read();
    for (int i = 1; i <= Q; ++i)  chkmax(mxc, p[i]);

    init();
    BFS();

    for (int i = 1; i <= Q; ++i) {
        if (!K) {
            puts(T >= p[i] ? "Yes" : "No");
            continue;
        } else if (K == 1) {
            if (T >= p[i]) { puts("Yes"); continue; }
            int fl = 0;
            for (int j = 1; j <= top; ++j) {
                if (c[j].x > p[i])  break;
                if (T - c[j].y + c[j].x >= p[i]) { fl = 1; break; }
            }
            puts(fl ? "Yes" : "No");
        } else {
            if (T >= p[i]) { puts("Yes"); continue; }
            int mn = (int)1e9, l = 1, fl = 0;
            for (int j = top; j >= 1; --j) {
                while (l < j && c[l].x + c[j].x <= p[i])  mn = min(mn, c[l].y - c[l].x), ++l;
                if (mn + c[j].y - c[j].x + p[i] <= T)  { fl = 1; break; }
                if (c[j].x <= p[i] && T - c[j].y + c[j].x >= p[i]) { fl = 1; break; }
            }
            puts(fl ? "Yes" : "No");
        }
    }

    return 0;
}

int read() {
    int x = 0, c = getchar();
    while (!isdigit(c))  c = getchar();
    while (isdigit(c))   x = x * 10 + c - 48, c = getchar();
    return x;
}
02-13 01:58
查看更多