Codeforces Round #353 (Div. 2)E

来源:互联网 发布:软件板块股票行情 编辑:程序博客网 时间:2024/05/22 15:36

题目大意

有N个车站,[1,n)的车站可以买到编号为i+1到ai的车站的票,设Pi,j为i车站到j车站的最少买票数,求所有Pi,j的和(1≤i<j≤n).

题解

定义dp[i]为从i到[i+1,n]的最少花费,dpi=dpj+j-ai+n-i(i<j≤ri).答案就是dpi的和(1≤i≤n).

因为i到[i+1,n]至少要n-i张票,(i,ai]只需要一张票就可以到达,因为(ai,n]不能直接到达,我们假设通过j间接到达,需要dpj张票,可是dpj包含的范围为(j,n],我们重复统计了(j,ai]所以我们减去ai-j.

从dpi=dpj+j-ai+n-i中发现dpi=xj+C(xj=dpj+j,C是一个与决策无关的常数).我们用线段树维护区间x最小值即可.

代码

#include <bits/stdc++.h>#define MAX 100100#define ls (o << 1)#define rs (o << 1 | 1)#define mid ((L + R) >> 1)using namespace std;typedef long long LL;LL dp[MAX];int r[MAX];LL tr[MAX << 2];int n;void update(int o, int L, int R, int pos, LL val) {    if (L == R) {        tr[o] = val;        return;    }    if (pos <= mid) {        update(ls, L, mid, pos, val);    } else {        update(rs, mid + 1, R, pos, val);    }    tr[o] = min(tr[ls], tr[rs]);}LL Q(int o, int L, int R, int l, int r) {    if (l <= L && R <= r) {        return tr[o];    }    LL res = 0x3f3f3f3f3f3f;    if (l <= mid) {        res = min(res, Q(ls, L, mid, l, r));    }    if (r > mid) {        res = min(res, Q(rs, mid + 1, R, l, r));    }    return res;}int main() {    int n;    scanf("%d", &n);    for (int i = 1; i < n; ++i) {        scanf("%I64d", &r[i]);    }    memset(tr, 0x3f, sizeof(tr));    update(1, 1, n, n, n);    LL ans = 0LL;    for (int i = n - 1; i; --i) {        dp[i] = Q(1, 1, n, i + 1, r[i]) - r[i] + (n - i);        update(1, 1, n, i, dp[i] + i);        ans += dp[i];    }    cout << ans << endl;    return 0;}
0 0
原创粉丝点击