面白かった!
問題概要
個の正の整数 を 個のグループに分ける。ただし、どのグループの要素数も 1 個以上 2 個以下でなければならない。
最適なグループ分けをしたときの、各グループの要素の総和の二乗の総和の最小値を求めよ。
制約
考えたこと
総和が一定なので、二乗和を最小化するためには、なるべく均等にすればよいということがわかる。
よって、 をソートして、小さい方から 個について、それらを逆順に残りの 個の に足していけば良いと予想を立てた。
- 小さい方から 個を、残りの小さい方から 個とペアを作って行く方法の中に最適解があること
- さらに、ペアにする際に大きさの逆順にするのがよいこと
は、それぞれ証明可能である。
計算量は、ソートする部分がボトルネックで となる。
コード
#include <bits/stdc++.h> using namespace std; int main() { long long N, M; cin >> N >> M; vector<long long> A(N); for (int i = 0; i < N; ++i) cin >> A[i]; sort(A.begin(), A.end()); vector<long long> B(M), C(N - M); for (int i = 0; i < N - M; ++i) C[i] = A[i]; for (int i = 0; i < M; ++i) B[i] = A[i + N - M]; reverse(C.begin(), C.end()); for (int i = 0; i < N - M; ++i) { B[i] += C[i]; } long long res = 0; for (int i = 0; i < M; ++i) { res += B[i] * B[i]; } cout << res << endl; }