ABC220 A - Find Multiple / B - Base K C++解答例
AtCoder Beginner Contest 220のA問題とB問題をC++で解きます。
A - Find Multiple
問題文をAtCoderのページより引用します。
問題文
以上 A 以下であるような B の倍数を、1つ出力してください。 C
条件を満たす数が存在しない場合は-1
を出力してください。
制約
1 \leq A \leq B \leq 1000 1 \leq C \leq 1000 - 入力はすべて整数
解答例
while
文を使った解法
解答例1:制約が緩いので、全探索することを考えてみましょう。
-1
を出力すればよいです。
以下の解答例では、answer
と、問題文の条件を満たす数が存在するかどうかを表す論理型変数ok
の2つを用い、while
文を使ってループを回しています。
条件を満たす数が見つかったらその時点でループを終了しています。
#include <iostream>
int main() {
int64_t A, B, C;
std::cin >> A >> B >> C;
int64_t answer = 0;
bool ok = false;
// B以下のCの倍数を全て見ていく
while (answer <= B) {
answer += C;
// 条件を満たす数が見つかればその時点でループを終了する
// このときのanswerが答えとなる
if (answer >= A && answer <= B) {
ok = true;
break;
}
}
// 条件を満たす数が存在すればその数を出力
if (ok) {
std::cout << answer << std::endl;
} else {
std::cout << -1 << std::endl;
}
return 0;
}
実際に提出したコードはこちら。
解答例2:整数の除算を利用した解法
公式解説で紹介されていた解法です。
この値が
#include <iostream>
int main() {
int64_t A, B, C;
std::cin >> A >> B >> C;
// xはB以下のCの倍数の中で最大の数
int64_t x = (B / C) * C;
if (x >= A) {
std::cout << x << std::endl;
} else {
std::cout << -1 << std::endl;
}
return 0;
}
実際に提出したコードはこちら。
B - Base K
問題文をAtCoderのページより引用します。
問題文
整数
, A が B 進法表記で与えられます。 K
を10進法表記で出力してください。 A \times B
制約
2 \leq K \leq 10 1 \leq A, B, \leq 10^5 , A は B 進法表記で与えられる。 K
解答例
「std::stoi
関数[1]やstd::stol
関数[2]などがまさにその機能を持っています。
これをそのまま使ってしまえば問題が解けるでしょう。
ただし、この問題ではオーバーフローに注意する必要があります。
制約を見ると、
そのため、この問題で考えられる最大の入力は、10進法で表記された
ここで、10,000,000,000
となりますが、32bitの符号付き整数型(int
型)が表せる最大の値は2,147,483,647
であり、32bitでは表現することができないことがわかります(符号なしにしても無理です)。
従って、この問題ではint
型やint32_t
型ではなく、long long
型かint64_t
型を使う必要があります。
また、上記の関数を使って解く場合も、std::stoi
やstd::stol
ではなく、std::stoll
関数を利用する必要があります。
std::stoll
関数を使って文字列をnullptr
を、第3引数に
#include <iostream>
#include <string>
int main() {
int64_t K;
std::cin >> K;
std::string A, B;
std::cin >> A >> B;
std::cout << std::stoll(A, nullptr, K) * std::stoll(B, nullptr, K) << std::endl;
return 0;
}
実際に提出したコードはこちら。
おまけ:進数変換関数の自作
例えば、3進数で表記された数
- 1桁目の数に
を掛けた値(3^0 = 1 )1 \times 3^0 = 1 - 2桁目の数に
を掛けた値(3^1 = 3 )0 \times 3^1 = 0 - 3桁目の数に
を掛けた値(3^2 = 9 )2 \times 3^2 = 18 - 4桁目の数に
を掛けた値(3^3 = 27 )1 \times 3^3 = 27
の総和が10進法表記したときの数になります。すなわち、
です。これを公式化すると、
と表せます。
実際にプログラムを組む際は、1桁目の数値にアクセスする際はS.at(N - 1)
のように書くことになり、for
文の記述が面倒になります。
なので、変換をする前に文字列の中身を逆転させてから計算するのが良いです。
std::reverse
関数を使えば文字列の順序を逆転させることができます。この関数を使うためには<algorithm>
ヘッダをインクルードする必要があります。
尚、文字列を逆転させた後、1桁目の値にアクセスする際はS.at(0)
と書くことになります。S.at(i - 1)
と書くことになるので注意しましょう。
int64_t base_k(std::string s, int64_t k) {
int64_t answer = 0;
// 各桁の値にかける係数
int64_t pow = 1;
// 文字列の順序を逆転させる
std::reverse(s.begin(), s.end());
for (int64_t i = 0; i < s.size(); i++) {
answer += static_cast<int64_t>(s.at(i) - '0') * pow;
pow *= k;
}
return answer;
}
プログラム全体は以下のようになります。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int64_t base_k(std::string s, int64_t k) {
int64_t answer = 0;
int64_t pow = 1;
std::reverse(s.begin(), s.end());
for (int64_t i = 0; i < s.size(); i++) {
answer += static_cast<int64_t>(s.at(i) - '0') * pow;
pow *= k;
}
return answer;
}
int main() {
int64_t K;
std::string A, B;
std::cin >> K >> A >> B;
std::cout << base_k(A, K) * base_k(B, K) << std::endl;
return 0;
}
実際に提出したコードはこちら。
Discussion