• 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;
    }
  • 相关阅读:
    java中this关键字
    java继承
    java super关键字
    java String类型存储详解
    java四种访问权限修饰符
    C/C++语言void及void指针深层探索【转】
    Linux Epoll介绍和程序实例【转】http://blog.csdn.net/sparkliang/article/details/4770655
    服务器与wp7的socket通信【转】 http://www.cnblogs.com/linzheng/archive/2011/06/21/2086456.html
    android关于socket编程,以聊天为例【转】http://hi.baidu.com/yaoyuanhuajx/item/9b93d7565f315ba9acc857d7
    Tesseract 3 语言数据的训练方法【转】http://blog.csdn.net/dragoo1/article/details/8439373
  • 原文地址:https://www.cnblogs.com/Saurus/p/6816770.html
Copyright © 2020-2023  润新知