個のものから 個除いたものを考えるのは色々定石がある!
問題概要
個の整数 が与えられる。
各 に対して、 を除外した 個の整数の最大値を求めよ。
制約
解法 (1):アドホックに考える
まずは素朴な解法を考えてみる。たとえば とかだったとき、 から [tex 3] や を除外したとしても、残りの整数値の最大値は 10 で変わらないであろう。
一方、 から を除外する場合においては、「 の中で二番目に大きい数」を出力する必要がある。よって
- の中の最大値を
- の中で二番目に大きい値を (最大値が複数個あるときは となりうる)
としたとき、
- のときは を出力
- のときは を出力
とすれば OK。
や を求めるのは、本来は でできる。でも を大きい順にソートして、「先頭の要素」「二番目の要素」をみるのが早いと思う。この場合の計算量は となる。
コード
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; vector<long long> A(N); for (int i = 0; i < N; ++i) cin >> A[i]; auto A2 = A; sort(A2.begin(), A2.end(), greater<long long>()); for (int i = 0; i < N; ++i) { if (A[i] != A2[0]) cout << A2[0] << endl; else cout << A2[1] << endl; } }
解法 (2):左右から累積和
個の要素から 1 個を除去したものを扱う問題では、
- 左右からの累積結果を求める
というアプローチがめちゃくちゃ有効。それで解ける類題は以下のようにたくさんある!
今回であれば
left[i]
← のうち、左から 個の最大値right[i]
← のうち、右から 個の最大値
とする。そうすると各 に対して次のように求められる。
max(left[i], right[N-i-1]
この方法でも の計算量で解ける。
コード
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; vector<long long> A(N), left(N+1, 0), right(N+1, 0); for (int i = 0; i < N; ++i) cin >> A[i]; for (int i = 0; i < N; ++i) { left[i+1] = max(left[i], A[i]); right[i+1] = max(right[i], A[N-i-1]); } for (int i = 0; i < N; ++i) cout << max(left[i], right[N-i-1]) << endl; }