公式

D - Tail of Snake 解説 by cn449


説明のため \(A, B, C\) を 0-indexed に置き換えます。 以降、この解説において数列はすべて 0-indexed です。

\(A, B, C\) の累積和を取ります。すなわち、長さ \(N + 1\) の数列 \(D, E, F\)\(\displaystyle D_i = \sum_{j = 0}^{i - 1} A_j, E_i = \sum_{j = 0}^{i - 1} B_j, F_i = \sum_{j = 0}^{i-1} C_j\) となるよう定めます。

最大化する対象 \(\displaystyle \sum_{i = 0} ^ {x - 1} A_i + \sum_{i = x}^{y - 1} B_i +\sum_ {i =y}^{N - 1} C_i\)\(D, E, F\) を用いて書き直すと \(D_x - E_x + E_y - F_y + F_N\) となります。

\(F_N\)\(x, y\) の選択によらない定数なので、目的は \(D_x - E_x + E_y - F_y\) を最大化することです。

数列 \(G, H\)\(G_i = D_i - E_i, H_i = E_i - F_i\) により定めると、\(G_x + H_y\) を最大化すればよいです。これは、先頭から累積 max を取りながら \(y\) を全探索することによって実現できます。具体的には、数列 \(I\)\(I_i = \displaystyle\max_{1 \leq j < i} G_j\) となるよう定めると、\(y\) を固定したときの最大値は \(I_y + H_y\) となります。

時間計算量は \(O(N)\) です。\(x = 0, x = y, y = N\) が許容されていないことに注意してください。

実装例

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (ll i = 0; i < (n); i++)
const ll INF = 1000000000000000010;
template<class T, class U> inline bool chmax(T& a, const U& b) { if (a < b) { a = b; return true; } return false; }

int main() {
	ll n;
	cin >> n;
	vector<ll> a(n), b(n), c(n);
	rep(i, n) cin >> a[i];
	rep(i, n) cin >> b[i];
	rep(i, n) cin >> c[i];
	vector<ll> d(n + 1), e(n + 1), f(n + 1);
	rep(i, n) {
		d[i + 1] = d[i] + a[i];
		e[i + 1] = e[i] + b[i];
		f[i + 1] = f[i] + c[i];
	}
	vector<ll> g(n + 1), h(n + 1);
	rep(i, n + 1) {
		g[i] = d[i] - e[i];
		h[i] = e[i] - f[i];
	}
	ll mx = -INF;
	ll ans = 0;
	for (int j = 1; j < n; j++) {
		chmax(ans, mx + h[j] + f[n]);
		chmax(mx, g[j]);
	}
	cout << ans << '\n';
}

投稿日時:
最終更新: