CF1651F 题解

发布时间 2023-11-05 16:37:21作者: 2021cjx

首先是数学表达这道题

考虑第 \(i\) 个怪物。

它跑完自己的全程扣得血是:

\[\sum\min\{c_j,m_{j,lst} + \Delta t \times r_j\} \]

\(\min\) 有点难搞,没啥好性质。

考虑拆开为两个部分:

\[\sum c_j + \sum (m_{j,lst} + \Delta t \times r_j) = \sum c_j + \sum m_{j,lst} + \sum \Delta t \times r_j \]

且取用的部分都与 \(\Delta t\) 有关,当 \(\Delta t \geq \frac{c_j}{r_j}\) 时取用 \(c_j\),反之亦然。

有上式可以想到二分,若前缀关于上式的值小于 \(h\) 则可取,反之亦然。

这样维护前缀的上式即可。

不想打主席树怎么办?分块处理。

维护块中上式,对于三种情况:

  • 非全零块暴力

  • 全零块 \(O(1)\) 计算。

  • 未能抹平块暴力。

均摊 \(O(n\sqrt{n})\)

#include <bits/stdc++.h>
#define int long long
const int maxn = 4e5;
using namespace std;
int s, n, q;
#define getbl(x) (x - 1) / s + 1
#define getbll(x) (x - 1) * s + 1
#define getblr(x) x *s
#define forbl(i, bl) for (int i = getbll(bl); i <= min(n, getblr(bl)); i++)
int c[maxn + 5], r[maxn + 5], m[maxn + 5];
int t[maxn + 5], h[maxn + 5];
int mxt;
int d[maxn + 5];
signed main() {
    freopen("dinosaurs.in", "r", stdin);
    freopen("dinosaurs.out", "w", stdout);
    scanf("%lld", &n);
    s = sqrt(n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld%lld", &c[i], &r[i]);
        m[i] = c[i];
    }
    scanf("%lld", &q);
    for (int i = 1; i <= q; i++) {
        scanf("%lld%lld", &t[i], &h[i]);
    }
    t[0] = 0;
    int ed = getbl(n);
    mxt = t[q];
    for (int i = 1; i <= ed; i++) {
        memset(d, 0, sizeof d);
        int j, k;
        forbl(j, i) {
            d[1] += r[j];
            if(c[j] / r[j] > maxn)continue;
            d[c[j] / r[j] + 1] -= r[j];
            if (c[j] % r[j]) {
                d[c[j] / r[j] + 1] += c[j] % r[j];
                d[c[j] / r[j] + 2] -= c[j] % r[j];
            }
        }
        for (j = 1; j <= maxn; j++) {
            d[j] += d[j - 1];
        }
        for (j = 1; j <= maxn; j++) {
            d[j] += d[j - 1];
        }
        int lst = 0;
        bool tag = 0;
        for (j = 1; j <= q; j++) {
            if (!h[j])
                continue;
            if (!tag) {
                forbl(k, i) { m[k] = min(m[k] + (t[j] - t[lst]) * r[k], c[k]); }
                bool clr = true;
                forbl(k, i) {
                    int ct = min(h[j], m[k]);
                    h[j] -= ct;
                    m[k] -= ct;
                    if (m[k])
                        clr = false;
                }
                if (clr)
                    tag = 1;
            } else {
                int dt = t[j] - t[lst];
                if (h[j] >= d[dt]) {
                    h[j] -= d[dt];
                } else {
                    forbl(k, i) { m[k] = min(m[k] + dt * r[k], c[k]); }
                    bool clr = true;
                    forbl(k, i) {
                        int ct = min(h[j], m[k]);
                        h[j] -= ct;
                        m[k] -= ct;
                    }
                    tag = 0;
                }
            }
            lst = j;
        }
    }
    int ans = 0;
    for (int i = 1; i <= q; i++) {
        ans += h[i];
    }
    printf("%lld", ans);
}