Codeforces 675E Trains and Statistic
我们考虑从一个点出发到达所有它后面所有位置所需要的次数和, 如果我们当前在x号点已经走了gg步,
那么我们肯定将x能到达的那些没走过的点标为gg + 1, 然后找到x 到a[ x ]上的a值最大的点y, 然后 x 走到 y,
然后重复上述过程。 那么我们用一个cnt[ i ]数组表示 <= i的点起始经过 i 这个点的有多少个点, 然后进行计算,
这时候我们会碰到一个问题, 那些cnt[ i ]个到达 i 的其实位置有可能已经处理掉了一些 i 后面的终点, 我们在
这些起始点转移到 i 之前把重复的减掉就好啦。
感觉网上用dp写法更好理解一些。。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); int n, a[N]; LL dis[N]; LL cnt[N]; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 PII mx[N << 2]; void build(int l, int r, int rt) { if(l == r) { mx[rt].fi = a[l]; mx[rt].se = l; return; } int mid = l + r >> 1; build(lson); build(rson); mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); } PII query(int L, int R, int l, int r, int rt) { if(l >= L && r <= R) return mx[rt]; int mid = l + r >> 1; if(R <= mid) return query(L, R, lson); else if(L > mid) return query(L, R, rson); else return max(query(L, R, lson), query(L, R, rson)); } int main() { scanf("%d", &n); for(int i = 1; i < n; i++) scanf("%d", &a[i]), cnt[i] = 0; build(1, n - 1, 1); LL ans = 0; for(int i = 1; i < n; i++) { cnt[i]++; PII tmp = query(i, a[i], 1, n - 1, 1); PII nxt = query(tmp.se, a[tmp.se], 1, n - 1, 1); ans += cnt[i] * (a[i] - i); ans += 2 * cnt[i] * (n - a[i]); ans -= cnt[i] * (tmp.fi - nxt.se); cnt[nxt.se] += cnt[i]; } printf("%lld\n", ans); return 0; } /* */