B - Achieve the Goal Editorial by TumoiYorozu
この解説は、C++ に入門したばかりの中高生レベルを想定して、考察の方法、コードの書き方の解説をします。
まず入力例1に注目して、解き方の方針を考えてみよう。 入力例1は、要するに
- 5教科のテストを受ける
- 今までのテストの成績は、\(8, 10, 3, 6\) 点であった。
- 平均点を7点以上にしたい。最後のテストでは何点取る必要があるだろうか?
というケースである。プログラミングのことは一旦忘れて、数学のテストで上の様な問題が出されたら、どう求めるだろうか?
いくつかのヒントに分けて書きましたが、ヒントを読んで分かりそうになったら自力で解けるかまた挑戦しましょう!
平均点を7点にしたいということは、5教科合計で7×5=35点を取るというのが目標である。 今までの4教科で、8+10+3+6=27点取れた。
5教科合計で7×5=35点取りたいので、最後のテストでは35-27 = 8 点取れば良い。 今までに取った合計点を計算して、目標の合計点からいままで取ったテストの合計点数を引くと、最後のテストで取るべき点数である。
今回は N-1 回のループなので、これを少しいじる必要がある。
以下のように書けば、N-1 個の a を受け取れる。 N-1個の a が受け取れたら、ヒント3で考えた目標の点数を計算する処理を書こう!
ヒント5内のコードの 処理① に合計点数を記録する変数 sum を作る。0で初期化するのを忘れずに。
処理② では、 最後にヒント3 を参考にして目標点 \(x\) を求めて、答えを表示しよう。
平均点を科目数で掛けると合計の目標点が得られる。それから今まで獲得したテストの点数を引けば、最後のテストで取るべき点数がわかる。 よって と書けば、入力例 1を試すと しかしこれでは処理③は不完全である。
入力例 2, 3 も試してみよう。そしてどうすれば良いか考えてみよう。あともう少しである。
ヒント8 までのコードを試すと、入力例2は-60が出力されるが、正解は0である。 この-60とはどういう意味かを考えると、「最後のテストでは-60点以上取れば良い」を意味する。
しかし、テストの点数は0点以上なので、答えとしては「0点以上取れば良い」と答えないといけないのである。
目標点数が0未満になってしまったら、0を出力すれば良い。
ヒント9 までのコードを試すと、入力例3は240が出力されるが、正解は-1である。 これは、テストはK点満点であるから、240点は取れない。問題文には『達成不可能である場合は、代わりに -1 を出力してください。』と書かれているので、今回は-1が答えである。
目標点数がKより大きくなってしまったら、-1を出力すれば良い。
入力例2の様な0以下のケースも考慮すると、以下のように書くと良い。 2行目は、目標点xが0未満のケースである。 xが0以上であれば3~9行目のelse パートが実行される。 その中で、またKと比較するifを書くことが出来る。 5 行目は x が K より大きいときに実行され、7 行目はそうじゃないときに実行される。 また以下のように書くと、よりスッキリする 目標達成に必要な合計点 \(x\) という変数(箱)を最初に用意して、各テストを受けるごとに \(x\) からテストの点数を引くと、最後に \(x\) に残った点数が、最後のテストで取るべき点数である。 ヒント1: 入力例1を手計算で解くときの方針
ヒント2: 入力例1を手計算で解くときの立式
ヒント3: プログラムで解く時の方針
ヒント4: テストの点数 A をループで受け取る
for (int i = 0; i < N; i++)
で N 回のループが書ける。 ヒント5: テストの点数 A をループで受け取る(具体的に編)
for (int i = 0; i < N-1; i++)
で N-1 回のループが書ける。#include <bits/stdc++.h>
using namespace std;
int main() {
int N, K, M;
cin >> N >> K >> M;
~~処理①~~
for(int i = 0; i < N-1; i++) {
int a;
cin >> a;
~~処理②~~
}
~~処理③~~
}
ヒント6: 目標の点数を計算する(方針)
ヒント7: 今まで取ったテストの合計点を求める
sum = sum + a
と書くことでsumに合計する事ができる。sum += a
と省略する書き方もある。#include <bits/stdc++.h>
using namespace std;
int main() {
int N, K, M;
cin >> N >> K >> M;
int sum = 0;
for(int i = 0; i < N-1; i++) {
int a;
cin >> a;
sum += a;
}
int x = 【目標点を計算する式を入れる】
~~処理③~~
}
ヒント8: 目標点を計算する。
int x = N * M - sum;
cout << x << endl;
8
という答えが返ってくる。 ヒント9: 入力例2のコーナーケース
ヒント9.1: 入力例2のコーナーケースの対処方法
ヒント10: 入力例3のコーナーケース
ヒント10.1: 入力例3のコーナーケースの対処方法
if (x < 0) {
cout << 0 << endl;
} else {
if (x > K) {
cout << -1 << endl;
} else {
cout << x << endl;
}
}
if (x < 0) {
cout << 0 << endl;
} else if (x > K) {
cout << -1 << endl;
} else {
cout << x << endl;
}
解答コード
#include <bits/stdc++.h>
using namespace std;
int main() {
int N, K, M;
cin >> N >> K >> M;
int sum = 0;
for(int i = 0; i < N-1; i++) {
int a;
cin >> a;
sum += a;
}
int x = N * M - sum;
if (x < 0) {
cout << 0 << endl;
} else if (x > K) {
cout << -1 << endl;
} else {
cout << x << endl;
}
}
少し違う書き方
#include <bits/stdc++.h>
using namespace std;
int main() {
int N, K, M;
cin >> N >> K >> M;
int x = N * M;
for(int i = 0; i < N-1; i++) {
int a;
cin >> a;
x -= a;
}
if (x < 0) {
cout << 0 << endl;
} else if (x > K) {
cout << -1 << endl;
} else {
cout << x << endl;
}
}
posted:
last update: