• 离线赛 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
    ", 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
    ", 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
    ", Ans[i]);
        return 0;
    }
    

    [in 2019.10.31 ]

  • 相关阅读:
    Direct3D轮回:游戏场景之天空
    Direct3D轮回:游戏特效之晴天光晕
    Direct3D轮回:基于.X文件的网格加载及渲染
    Direct3D轮回:游戏特效之风动、雾化
    Direct3D轮回:游戏场景之陆地
    Direct3D轮回:基于ID3DXSprite的2D元素绘制
    Direct3D轮回:基于HLSL实现D3D中的光照特效
    Direct3D轮回:构建基于Direct3D的通用摄影机类
    Direct3D轮回:构建基于DirectInput机制的键盘输入设备
    剪切上传图片源码
  • 原文地址:https://www.cnblogs.com/Ameiyo/p/11771747.html
Copyright © 2020-2023  润新知