zoukankan      html  css  js  c++  java
  • 线段树+dp+贪心 Codeforces Round #353 (Div. 2) E

    http://codeforces.com/contest/675/problem/E

    题目大意:有n个车站,每个车站只能买一张票,这张票能从i+1到a[i]。定义p[i][j]为从i到j所需要买的最小票数。问sigma(p)的和是多少。

    思路:感觉我的dp定义能力还是太弱了啊,我刚开始还定义成dp[i]表示1~i-1到i所需要的最小花费和,后来发现这样子我转移不了啊!!

    于是重新定义dp[i]表示从i出发到i+1~n所需要的最小票数,然后这样定义就能很好的解决问题啦。然后我们每次贪心的选取j = i+1~a[i]中的a[j]跑的最远的那个,然后进行转移就好了,具体的用线段树维护一下区间吧。

    TAT感觉是不难的题目

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 1e5 + 5;
    int a[maxn];
    int n;
    struct Tree{
        int lpos, rpos;
        Tree(int l = 0, int r = 0): lpos(l), rpos(r){}
    }tree[maxn << 2];
    
    inline void push_up(int o){
        int lb = o << 1, rb = o << 1 | 1;
        tree[o].rpos = max(tree[lb].rpos, tree[rb].rpos);
        if (tree[lb].rpos >= tree[rb].rpos) {
            tree[o].lpos = tree[lb].lpos;
        }
        else tree[o].lpos = tree[rb].lpos;
    }
    
    void build_tree(int l, int r, int o){
        if (l == r){
            tree[o].rpos = a[l];
            tree[o].lpos = l;
            return ;
        }
        int mid = (l + r) / 2;
        if (l <= mid) build_tree(l, mid, o << 1);
        if (r > mid) build_tree(mid + 1, r, o << 1 | 1);
        push_up(o);
    }
    
    Tree query(int l ,int r, int ql, int qr, int o){
        if (ql <= l && qr >= r){
            return tree[o];
        }
        Tree ans, re;
        ans.lpos = re.lpos = ans.rpos = re.rpos = 0;
        int mid = (l + r) / 2;
        if (ql <= mid)
            ans = query(l, mid, ql, qr, o << 1);
        if (qr > mid)
            re = query(mid + 1, r, ql, qr, o << 1 | 1);
        if (ans.rpos < re.rpos) ans = re;
        return ans;
    }
    
    LL dp[maxn];///定义从i开始走到n所需要的最小花费
    int main(){
        scanf("%d", &n);
        a[n] = n;
        for (int i = 1; i <= n - 1; i++) scanf("%d", a + i);
        memset(tree, 0, sizeof(tree));
        build_tree(1, n, 1);
        LL ans = 0;
        for (int i = n - 1; i > 0; i--){
            Tree pos = query(1, n, i + 1, a[i], 1);
            dp[i] = n - i + dp[pos.lpos] - (a[i] - pos.lpos);
            ans += 1LL * dp[i];
        }
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    mongo批量删除js示例
    Mongo压测介绍
    线性代数学习笔记(1)--二维向量点积本质(仅供自己理解)
    墨菲定律的正确解读
    spring cloud 2020.0.1踩坑记录-bootstrap不生效等
    记一次网络质量原因导致接口调用超时的调查过程
    .NET Debugging Demos Lab 2: Crash
    .NET Debugging Demos Lab 3: Memory
    Hang caused by GC
    .NET Debugging Demos Lab 4: High CPU hang
  • 原文地址:https://www.cnblogs.com/heimao5027/p/5924128.html
Copyright © 2011-2022 走看看