[SOJ #721]第三送分题(2019-11-14考试)/[CF675E]Trains and Statistic

题目大意

在一条直线上有\(n\)个点。在第\(i\)个点可以花费\(1\)的代价到达\((i,a_i]\)中任意一点,用\(S[i][j]\)表示从点\(i\)到点\(j\)的最少花费,求\(\sum\limits_{1\leqslant i< j\leqslant n}S[i][j]\)\(n\leqslant10^5\)

题解

若从点\(i\)开始,那么到\((i,a_i]\)的代价为\(1\),令\(p\)\((i,a_i]\)\(a_p\)最大的点,则到\((a_i,a_p]\)的代价为\(2\)。那么,若知道了点\(\sum\limits_{j=p+1}^nS[p][j]\),那么\(\sum\limits_{j=i+1}^nS[i][j]=\sum\limits_{j=p+1}^nS[p][j]+(n-a_i)+(p-i)\)。就可以倒着求出每个点到后面每个点的代价和。

卡点

C++ Code:

#include <cstdio>
#include <algorithm>
#include <iostream>
const int maxn = 1e5 + 10;

int n, a[maxn], S[maxn], top;
long long ans, f[maxn];

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	std::cin >> n;
	for (int i = 1; i < n; ++i) std::cin >> a[i];
	f[n] = 0, S[top = 1] = n;
	for (int i = n - 1; i; --i) {
		int pos = *std::lower_bound(S + 1, S + top + 1, a[i], std::greater<int> ());
		while (top && a[i] >= a[S[top]]) --top;
		S[++top] = i, f[i] = f[pos] + n - a[i] + pos - i, ans += f[i];
	}
	std::cout << ans << '\n';
	return 0;
}

posted @ 2019-11-14 16:11  Memory_of_winter  阅读(138)  评论(0编辑  收藏  举报