您的位置:首页 > 其它

Codeforces Round #353 (Div. 2)E

2016-05-19 21:22 260 查看

题目大意

有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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces