けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 063 C - Bugged (4Q, 茶色, 300 点)

面白い問題。最近はこういうの、あまり見ないかもしれない。

問題概要

 N 個の正の整数  s_{1}, s_{2}, \dots, s_{N} が与えられる。

これらからいくつか選んで総和をとる。ただし、その値が 10 の倍数である場合には、その値は 0 になってしまう。

この値の最大値を求めよ。

制約

  •  1 \le N \le 100
  •  1 \le s_{i} \le 100

考えたこと

正の整数をいくつか選ぶ方法をすべて試すことを考えると、 2^{N} 通りの方法がある。ビット全探索を用いると、この  2^{N} 通りの方法をすべて調べることができる。しかし、 N \le 100 なので、この方法では間に合わない。

まず、「すべて足す」方法を試してみよう!!! 

もし仮に、 s_{1} + s_{2} + \dots + s_{N} ( = A とする) が 10 の倍数でないならば、その値が最大である。

それでは、 A が 10 の倍数になってしまったときはどうしたらよいだろうか。その場合は、 A から 1 個の値を引いたものを試していくことが考えられるだろう。

ここで重要な考察として、もし  A, A - s_{1}, A - s_{2}, \dots, A - s_{N} がすべて 10 の倍数であるならば、結局  s_{1}, s_{2}, \dots, s_{N} がすべて 10 の倍数であるということが分かる。そして、 s_{1}, s_{2}, \dots, s_{N} がすべて 10 の倍数であるとき、これらからどのように選んで総和をとっても 10 の倍数になってしまうのだ(この場合の答えは 0)。

以上の考察をもとに、次の 3 つの場合に分けて考えると良さそうだと分かる。


  •  s_{1}, s_{2}, \dots, s_{N} がすべて 10 の倍数であるとき:答えは 0
  •  A = s_{1} + \dots + s_{N} が 10 の倍数でないとき:答えは  A
  •  A が 10 の倍数であって、 s_{1}, s_{2}, \dots, s_{N} の中に 10 の倍数でないものがあるとき:(後述)

3 つ目の場合を最後に考える。

 A が 10 の倍数であって、 s_{1}, s_{2}, \dots, s_{N} の中に 10 の倍数でないものがあるとき

この場合は、  A - s_{1}, A - s_{2}, \dots, A - s_{N} の中に 10 の倍数でないものが存在する(そうでなければ、 s_{1}, s_{2}, \dots, s_{N} がすべて 10 の倍数になるため)。直感的には、そのうち最大の数を答えればよさそうだ。

気になるのが、 A から 2 個以上の値を引く場合も考えた方が、答えが大きくなるケースもあるのではないか??ということだ。これについて一応考えておこう。少し考えると、次のことが示せる。


 A, a, b を正の整数とし、 A は 10 の倍数であるとする。

 A - a - b が 10 の倍数でないならば、 A - a, A - b のいずれかは 10 の倍数でない。


証明

 A - a A - b がともに 10 の倍数であると仮定する。このとき、 A が 10 の倍数であることから、

 (A - a) + (A - b) - A (=  A - a - b)

も 10 の倍数である。これは矛盾である。

(証明終わり)

 A - a \gt A - a - b
 A - b \gt A - a - b
であるから、 A から 2 個の値を引いたものが最大になることはないと言える(3 個以上の値を引いたものが最大になることがないことも同様に言える)。

コード

以上の解法は  O(N) の計算量で実装できる。

#include <bits/stdc++.h>
using namespace std;
                                 
int main() {
    int N, sum = 0, res = 0;
    cin >> N;
    vector<int> s(N);
    for (int i = 0; i < N; i++) {
        cin >> s[i];
        sum += s[i];
    }

    if (sum % 10 != 0) res = sum;
    else {
        for (int i = 0; i < N; i++) {
            if ((sum - s[i]) % 10 != 0) res = max(res, sum - s[i]);
        }
    }
    cout << res << endl;
}