パズルだ!!
問題概要
正の整数 が与えられる。 個の正の整数 を用意して、
- がそれぞれ 個ずつあるとして
- それらの足し引きによって までの整数がすべて作れる
という条件を満たすような最小の を求めよ。
制約
考えたこと
の場合は結構な有名問題!!!
こういうの一見して
とやると効率が良さそうに思える。実際、「足し引き」のうち「足す」のみを許容していたら、これがピッタリ。
1 = 1 2 = 2 3 = 1 + 2 4 = 4 5 = 1 + 4 6 = 2 + 4 7 = 1 + 2 + 4 8 = 8 9 = 1 + 8 10 = 2 + 8 ...
という感じ。こんな風に、「任意の整数は、二冪の和で表せる」というのは、AtCoder の構築問題で非常に多く見られる典型!!!
しかし「引き」も認めると自由度が上がる。実は二冪の代わりに三冪にすると良いのだ!!!
実際こんな感じ
1 = 1 2 = -1 + 3 3 = 3 4 = 1 + 3 5 = -1 - 3 + 9 6 = -3 + 9 7 = 1 - 3 + 9 8 = -1 + 9 9 = 9 10 = 1 + 9 11 = -1 + 3 + 9 12 = 3 + 9 13 + 1 + 3 + 9 14 = -1 - 3 - 9 + 27 15 = -3 - 9 + 27 ...
ちょうどいい感じに、切れ目なく作れることがわかる。実はこれは平衡三進法展開とかよばれてたと思う。それを題材にした問題も過去に TopCoder で出ている。
今回の問題
今回のように、 が 個ずつ作れるようになっても、ちょっとした拡張で解くことができる。具体的には
で OK!たとえば のとき
として
1 = 1 2 = 1 + 1 3 = 1 + 1 + 1 4 = -1 - 1 - 1 + 7 5 = -1 - 1 + 7 6 = -1 + 7 7 = 7 8 = 1 + 7 + ... + 24 = 1 + 1 + 1 + 7 + 7 + 7 + 25 = -1 - 1 - 1 - 7 - 7 - 7 + 49 + 26 = -1 - 1 - 7 - 7 - 7 + 49 + ...
という感じ。
#include <iostream> using namespace std; long long M, K; int main() { long long M, K; cin >> M >> K; long long wa = 0; long long seki = 1; int res = 0; while (wa < M) ++res, wa += seki*K, seki *= K*2+1; cout << res << endl; }