計算量の意識が必要になる良問!
問題概要
個の整数からなる数列
が与えられる。これを左右に 2 つに分ける(左右ともに 1 個以上はとる)。
左側の要素の総和を 、右側の要素の総和を
とするとき、
の最小値を求めよ。
制約
考えたこと
もし計算時間を考えなくて良いならば、「左側の要素を何個にするか」で全探索する方法が考えられるだろう。探索候補は 通りある。そのそれぞれについて、左右の総和を愚直に計算すると
の計算量を要するので、全体として
の計算量となる。このままでは TLE してしまうので、高速化しよう。
まず、左側の総和については、それを表す変数 sum を用意しておき、左側の要素の個数を増やす度に sum に加算していくようにすればよい。
右側の総和については、あらかじめ数列全体の総和 sum_all を求めておけば、sum_all - sum によって求められる。
この方法によって、「左側の要素の個数」を決めたときの、左右の総和を求めるのは の計算量でこなせるので、全体として
の計算量となる。
コード
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; long long all_sum = 0; vector<long long> a(N); for (int i = 0; i < N; i++) { cin >> a[i]; all_sum += a[i]; } long long res = 1LL << 60, sum = 0; for (int i = 0; i < N - 1; i++) { // a[i] までの和 sum += a[i]; // もう片方の総和 long long other = all_sum - sum; // diff を更新 res = min(res, abs(sum - other)); } cout << res << endl; }