TIOJ 2348:F. 守護魔摩市

TIOJ 2348:F. 守護魔摩市


題目大意:連結

解法:用倍增,存每個時間魔力值是 $A$,忍耐值是 $0$ 時,下一個人在哪,還有下一個魔力值 $A$、忍耐值 $0$ 的時間,還有之間 $f$ 的總和。每次詢問用建好的倍增算答案。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

const int N = 5e5 + 5;
const int H = __lg(N);

int n, q, A, B;
string s;
int R[N];
ll ans, sum[H + 1][N];
pair<int, int> to[H + 1][N];

inline ll cal(int l, int r) {
    return l <= r ? 1ll * (l + r) * (r - l + 1) / 2 : 0;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> q >> A >> B;
    cin >> s, s = " " + s;
    R[n + 1] = n + 1;
    for (int i = n; i >= 1; i--) {
        R[i] = R[i + 1];
        if (s[i] == '1') R[i] = i;
    }
    to[0][n + 1] = {n + 1, n + 1};
    for (int i = 1; i <= n; i++) {
        auto &[x, y] = to[0][i];
        y = R[i + 1];
        if (y > n) x = y;
        else if (i + B >= y) {
            x = y;
            sum[0][i] = 1ll * A * (y - i);
        } else if (i + A + B >= y) {
            int len = y - i - B;
            x = min(n + 1, i + B + 2 * len);
            sum[0][i] = 1ll * A * B + cal(A - len, A) + cal(A - len + 1, A - 1);
        } else {
            x = min(n + 1, y + A);
            sum[0][i] = 1ll * A * (A + B);
        }
    }
    for (int i = 1; i <= H; i++) for (int j = 1; j <= n + 1; j++) {
        auto &[nx, ny] = to[i - 1][j];
        to[i][j] = to[i - 1][nx];
        sum[i][j] = sum[i - 1][j] + sum[i - 1][nx];
    }
    while (q--) {
        int l, r, pos;
        cin >> l >> r;
        pos = R[l];
        if (pos > r) {
            cout << "0\n";
            continue;
        }
        ans = cal(0, A - 1);
        pos = min(pos + A, n + 1);
        for (int i = H; i >= 0; i--) if (to[i][pos].second <= r) {
            ans += sum[i][pos];
            pos = to[i][pos].first;
        }
        ans += 1ll * A * B + cal(0, A);
        cout << ans << '\n';
    }
}

我的分享就到這裡結束了,如果喜歡我的 $\text{Blog}$,歡迎追蹤!

留言

熱門文章