見出し画像

ARC106-Aの解答

AtCoder Regular Contest106-A 106の解答を書いていきます。問題はこちらから。

Difficulty 180 (灰色)

問題

整数 n が与えられる。次式を満たす正の整数 a, b の組み合わせを求めよ。

3 ^ a + 5 ^ b = n

また、存在しない場合は -1 を出力します。

考察

まず、愚直に全探索ができるかどうか考えました。制約は

1 <= n <= 10^18

です。1 から 10^18 ですと、O(n)でも計算が間に合いませんが、今回は a, b が数字の肩に乗っているので a が小さくともすぐに 10^18 乗まで達します。具体的には

3^37 < 10 ^ 18 < 3^38
5^25 < 10 ^ 18 < 5^26

ですので、 37 * 25 = 925 回で全探索が完了します。全部調べて、見つからなければ -1 としましょう。

とはいうものの、37とか25という数字を求めるのも面倒くさいので、a = 1として、条件式が n を超えるまで b を増やしながら回しましょう。超えてしまったら、a = 2として同様に b を増やしていきましょう。

オーバーフローに関して補足します。最大ケースである n <= 10^18 にて、5*10^18 という数字がざっくりと考えた最大の数となります(実際には取りませんが)。long longの最大値は9*10*^18よりも大きいので、この型で宣言をしておけば、オーバーフローは発生しません。

実装

#include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;++i)
#define reps(i,s,n) for(int i=s;i<n;++i)
using ll = long long;
using namespace std;

int main()
{
   ll n;
   cin >> n;
   int a = 0;
   int b = 0;
   ll ca = 1;
   ll cb = 1;

   while (1)
   {
       ++a;
       ca *= 3;
       cb = 1;
       b = 0;
       while (1)
       {
           ++b;
           cb *= 5;
           ll s = ca + cb;
           if (s == n)
           {
               cout << a << " " << b << endl;
               return 0;
           }
           if (s > n) break;
       }
       if (ca > n) break;

   }
   cout << -1 << endl;
   return 0;
}

おわりに

C++にpowという関数がありますが、 a や b は1つずつ増やしていくので、while文で前状態を使いながら探索するのが効率よいと思います。powの内部がどうなっているのかは詳しくは知りませんが、、

あと、オーバーフローの対処が大変な言語もあるみたいですね。こういうとき、pythonの力を借りたくなりますね。この問題のように計算量が少ないなど、pythonで通せる問題はおとなしくそちらで書いた方が、試験中の解答時間を削減できるかもしれません。

この記事が気に入ったらサポートをしてみませんか?