• arc073 F many moves(dp + 线段树)


    设dp[i][y]表示一个点在x[i],另一个点在y时最小要走的步数

    那么有以下转移

    对于y != x[i-1]的状态,可以证明,他们直接加|x[i] - x[i-1]|即可(如果有其他方案,不符合对dp的定义)

    当y == x[i-1]时,它可以由其他所有状态转移过来, dp[i][x[i-1]] = min(dp[i][y] + |y - x[i]|)

    把绝对值拆出来,就是需要维护一个dp[i][y] + y 和dp[i][y] - y,建立两个线段树即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    using namespace std;
    typedef long long LL;
    const int maxn = 2e5 + 100;
    LL Plus[maxn*4], Minus[maxn*4], tag[maxn*4];
    inline LL abs(LL x) { return x < 0 ? -x : x; }
    inline void Puttag(int o, LL v){
        Plus[o] += v;
        Minus[o] += v;
        tag[o] += v;
    }
    inline void Pushdown(int o){
        if(!tag[o]) return;
        Puttag(o*2, tag[o]);
        Puttag(o*2+1, tag[o]);
        tag[o] = 0;
    }
    inline void Maintain(int o){
        Plus[o] = min(Plus[o*2], Plus[o*2+1]);
        Minus[o] = min(Minus[o*2], Minus[o*2+1]);
    }
    inline bool Cut(int x) { return false; }
    inline bool Check(int x) { return true; }
    inline void Change(int o, int l, int r, int L, int R, LL v){
        if(L > r || R < l || Cut(o)) return;
        if(L <= l && r <= R && Check(o)){
            Puttag(o, v); return;
        }
        int mid = (l+r)/2; Pushdown(o);
        Change(o*2, l, mid, L, R, v);
        Change(o*2+1, mid+1, r, L, R, v);
        Maintain(o);
    }
    inline long long Query(int o, int l, int r, int L, int R, int ty){
        if(L > r || R < l || Cut(o)) return 1e18;
        if(L <= l && r <= R){
            return ty ? Plus[o] : Minus[o];
        }
        int mid = (l+r)/2; Pushdown(o);
        ans = min(Query(o*2+1, mid+1, r, L, R, ty), Query(o*2, l, mid, L, R, ty));
        Maintain(o);
        return ans;
    }
    inline void Insert(int o, int l, int r, int k, LL v, int ty){
        if(l == r) {
            if(ty) Plus[o] = v; else Minus[o] = v;
            return;
        }
        int mid = (l+r)/2; Pushdown(o);
        if(k <= mid) Insert(o*2, l, mid, k, v, ty);
        else Insert(o*2+1, mid+1, r, k, v, ty);
        Maintain(o);
    }
    
    int N, Q, A, B;
    int x[maxn];
    int main(){
        scanf("%d %d %d %d", &N, &Q, &A, &B);
        for(int i = 1; i <= Q; i++) scanf("%d", &x[i]);
        x[0] = B;
        // dp[i][x] = dp[i-1][x] + ||
        // dp[i][x[i-1]] = all(dp[i-1][x]+|x-x[i]|)
        // x <= x[i] -> dp[i-1][x] + x[i] - x
        // x > x[i] -> dp[i-1][x] + x - x[i]
        memset(Plus, 1, sizeof(Plus));
        memset(Minus, 1, sizeof(Minus));
        Insert(1, 1, N, A, A, 1);
        Insert(1, 1, N, A, -A, 0);
        for(int i = 1; i <= Q; i++){
            LL ans = min(Query(1, 1, N, 1, x[i], 0) + x[i], Query(1, 1, N, x[i]+1, N, 1) - x[i]);
            Change(1, 1, N, 1, x[i-1]-1, abs(x[i] - x[i-1]));
            Change(1, 1, N, x[i-1]+1, N, abs(x[i] - x[i-1]));
    
            Insert(1, 1, N, x[i-1], ans + x[i-1], 1);
            Insert(1, 1, N, x[i-1], ans - x[i-1], 0);
        }
        LL ans = 1e18;
        for(int i = 1; i <= N; i++){
            ans = min(ans, Query(1, 1, N, i, i, 0) + i);
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    vue-element-admin项目install出现的问题
    关于html5 Notification桌面通知无法在谷歌浏览器显示的问题
    C#调用存储过程执行缓慢,但在数据库中执行却很快的问题
    IdnentiyServer-使用客户端凭据访问API
    IdentityServer开题篇
    IdentityServer4客户端JWT解密实现(基于.net4.0)
    iis访问网络路径映射问题(UNC share)
    .net core部署在iis上
    git blame 查找修改者
    代码管理工具-将项目文件打成tar包,并且排除.git目录
  • 原文地址:https://www.cnblogs.com/Saurus/p/6816770.html
Copyright © 2020-2023  润新知