离线赛 2019.10.31

2019.10.30

\[ Ameiyo \]



A

挺简单的一道 Dp 。。。看 这个博客


B

其实可以用 dijsktra 做这道题,但是每次用来更新的都是自己的次小值。

因为当你走到当前点时,老虎会让你不能走最小值,所以是用次小值更新。

每次也是拿次小值最小的点出来更新。

ll mi[N][2];

struct NODE {
    int id;
    ll w;
    inline int operator < (const NODE &__) const {
        return w > __.w;
    }
} ;

priority_queue < NODE > Q;

int main() {
    memset(mi, 0x3f, sizeof mi);

    n = read<int>(), m = read<int>(), q = read<int>();
    rep (i, 1, m) {
        int x = read<int>() + 1, y = read<int>() + 1, c = read<int>();
        Addedge(x, y, c), Addedge(y, x, c);
    }
    rep (i, 1, q) {
        int x = read<int>() + 1;
        mi[x][0] = mi[x][1] = 0, Q.push((NODE) { x, 0 });
    }

    while (!Q.empty()) {
        int u = Q.top().id; Q.pop();
        if (mk[u]) continue;
        mk[u] = true;
        for (int i = head[u], v; i; i = edge[i].nex) {
            v = edge[i].to;
            if (mk[v]) continue;
            ll tmp = mi[u][1] + edge[i].cost, flag = false;
            rep (d, 0, 1)
                (tmp < mi[v][d] && (swap(tmp, mi[v][d]), flag = true));
            if (flag) Q.push((NODE) { v, mi[v][1] });
        }
    }

    printf("%lld\n", mi[1][1]);
    return 0;
}

C

一道比较难想到的统计题。

有两种做法,但是两种做法都是基于暴力的 Dp (这个总要会吧。。),然后枚举所有询问跨越的点,通过对点两边的预处理然后合并。

  1. 分块,复杂度 $ O((n + q) * \sqrt {n * l}) $

其实我觉得这不能叫分块。。。

我们每 $ C $ 个点设置一个点,对于所有的点,我们处理出其左边一部分不选的情况下,左边每个点到他的 Dp 值,右边也一样。这样查询的时候就只用考虑中间有一块合并起来做贡献的情况。

因为 $ l $ 很小,所以每次直接暴力处理就行了。

const ll N = 100005, INF = 1e9;
const ll M = 55;
const int C = 4700;


#define max(a, b) ((a) > (b) ? (a) : (b))

int n, m, k, A[N], S[N], tmp[N], tot;
int fl[M][N], fr[M][N];

struct QUERY {
    int bl, l, r, id;
    inline int operator < (const QUERY &__) const {
        return bl < __.bl;
    }
}  Query[N];

int cur, Ans[N];

void Solve(int id) {
    memset(fl, 0, sizeof fl);
    memset(fr, 0, sizeof fr);
    rep (i, 0, k + 1) {
        dep (j, id - i - k + 1, 1)
            fl[i][j] = max(fl[i][j + 1],
                           fl[i][j + k] + S[j + k - 1] - S[j - 1]);
        rep (j, id + i + k - 1, n)
            fr[i][j] = max(fr[i][j - 1],
                           fr[i][j - k] + S[j] - S[j - k]);
    }
    for ( ; cur <= tot && Query[cur].bl == id; ++cur) {
        int l = Query[cur].l, r = Query[cur].r, ans = fl[1][l] + fr[0][r];
        rep (x, max(0, l + k - id - 1), min(k, r - id))
            ans = max(ans, fl[k - x][l] + fr[x + 1][r]
                            + S[id + x] - S[id + x - k]);
        Ans[Query[cur].id] = ans;
    }
}

int main() {
    n = read<int>(), k = read<int>();
    rep (i, 1, n) S[i] = S[i - 1] + (A[i] = read<int>());
    m = read<int>();
    rep (i, 1, m) {
        int l = read<int>(), r = read<int>();
        if (r - l + 1 <= C) {
            rep (i, k, r - l + 1)
                tmp[i] = max(tmp[i - 1],
                             tmp[i - k] + S[i + l - 1] - S[i + l - 1 - k]);
            Ans[i] = tmp[r - l + 1];
        } else Query[++tot] = (QUERY) { r / C * C, l, r, i };
    }

    sort(Query + 1, Query + tot + 1);

    cur = 1;
    rep (i, 1, n / C) Solve(i * C);

    rep (i, 1, m) printf("%d\n", Ans[i]);
    return 0;
}
  1. 分治,复杂度 $ O(n * \log n * k + q * k) $

每次选出来的点是当前区间的 $ mid $ ,其他同上。

const ll N = 100005, INF = 1e9;
const ll M = 55;

#define max(a, b) ((a) > (b) ? (a) : (b))

int n, m, k, A[N], S[N];

struct QUERY { int id, l, r; } ;
vector < QUERY > Que[N << 2];
int Ans[N];

#define ls (p << 1)
#define rs (p << 1 | 1)
void Push(int p, int l, int r, int L, int R, int id) {
    if (l == r) return (void) (Que[p].push_back((QUERY) { id, L, R }));
    int mid = (l + r) >> 1;
    if (R <= mid) Push(ls, l, mid, L, R, id);
    else if (L > mid) Push(rs, mid + 1, r, L, R, id);
    else Que[p].push_back((QUERY) { id, L, R });
}

int fl[M][N], fr[M][N];
void Solve(int p, int l, int r) {
    int mid = (l + r) >> 1, siz = Que[p].size();
    if (l != r) Solve(ls, l, mid), Solve(rs, mid + 1, r);
    if (!siz) return ;
    rep (i, 0, k) {
        rep (j, l, r) fl[i][j] = fr[i][j] = 0;
        dep (j, mid - i - k + 1, l)
            fl[i][j] = max(fl[i][j + 1],
                           fl[i][j + k] + S[j + k - 1] - S[j - 1]);
        rep (j, mid + i + k - 1, r)
            fr[i][j] = max(fr[i][j - 1],
                           fr[i][j - k] + S[j] - S[j - k]);
    }
    rep (i, 0, siz - 1) {
        int id = Que[p][i].id, l = Que[p][i].l, r = Que[p][i].r;
        int ans = fl[1][l] + fr[0][r];
        rep (x, max(0, l + k - mid - 1), min(k, r - mid))
            ans = max(ans, fl[k - x][l] + fr[x + 1][r]
                            + S[mid + x] - S[mid + x - k]);
        Ans[id] = ans;
    }
}

int main() {
    n = read<int>(), k = read<int>();
    rep (i, 1, n) S[i] = S[i - 1] + (A[i] = read<int>());
    m = read<int>();
    rep (i, 1, m) {
        int l = read<int>(), r = read<int>();
        Push(1, 1, n, l, r, i);
    }

    Solve(1, 1, n);

    rep (i, 1, m) printf("%d\n", Ans[i]);
    return 0;
}

\[ in \ 2019.10.31 \]

猜你喜欢

转载自www.cnblogs.com/Ameiyo/p/11771747.html