CF 675ETrains and Statistic(线段树 + Dp)

来源:互联网 发布:金仕达期货交易软件 编辑:程序博客网 时间:2024/06/04 01:03

题目:

给你 n 个车站, 第 i 个车站能买到 i+1 到 A[i] 的票, 现在有 P[i][j] 为 车站 i 到 j 所需要的最少的买票次数。 求所有的 P[i][j] 的和。

分析:

首先, 对于在车站 i , 做到最后一站, 我们贪心买票的思路是 在 i+1 到 A[i] 车站中取最大值,在那一站再去买票, 即可最少到达最后一站。在求解过程中, 有很多重复步骤, 故可以Dp从后往前扫利用之前的状态。题目又是求解∑, 故Dpi 就表示 后缀和了。我们便可以很快得出Dp方程了Dp[i] = Dp[m] + n - i - (A[i] - m);而 m = max(A[i+1], A[i+2] ... A[A[i]]);m 用线段树维护就好了。

Code:

/** * @Author:   Aoxuets * @DateTime:   2016-06-06 15:58:29 */#include <bits/stdc++.h>#define lson l, m, rt << 1#define rson m+1, r, rt << 1|1using namespace std;typedef long long LL;const int maxn = 100000 + 131;struct Node {    int id, val;    Node() {}    Node(int i, int v) : id(i), val(v) {}    bool operator < (const Node a) const {        return  val == a.val ? id < a.id : val < a.val;    }} Sum[maxn << 2];int A[maxn];void PushUp(int rt) {    Sum[rt] = max(Sum[rt<<1], Sum[rt<<1|1]);}void Build(int l, int r, int rt) {    if(l == r) {        Sum[rt] = Node(l, A[l]);        return ;    }    int m = (l + r) >> 1;    Build(lson), Build(rson);    PushUp(rt);}Node Q_Max(int L, int R, int l, int r, int rt) {    if(L <= l && r <= R) {        return Sum[rt];    }    int m = (l + r) >> 1;    Node ret = Node(-1,-1);    if(L <= m) ret = max(ret, Q_Max(L, R, lson));    if(R > m)  ret = max(ret, Q_Max(L, R, rson));    return ret;}LL Dp[maxn];int main() {    int n;    cin >> n;    for(int i = 1; i < n; ++i) {        cin >> A[i];    }    A[n] = n;    Build(1, n, 1);    LL Ans = 0;    for(int i = n-1; i >= 1; --i) {        int Max = Q_Max(i+1, A[i], 1, n, 1).id;        Dp[i] = Dp[Max] + n - i - (A[i]-Max);        Ans += Dp[i];    }    cout << Ans << endl;}
0 0
原创粉丝点击