読者です 読者をやめる 読者になる 読者になる

yukicoder no.25

問題文
http://ch.nicovideo.jp/programing/blomaga/ar620922

解説(と考えた過程)
有限小数で表せるということは、分子を整数、分母を 10^n で表せるということである。
分母が 10^n すなわち (2^n) * (5^n) で表せるためには、M が 2 または 5 の素因数のみを持つことが必要である。後は、2 と 5 の素因数の少ない方を N にかけてやれば、元の分数 N / M を (整数) / (10^n) という形で表すことができるようになる。

ただここで、普通にやるとオーバーフローしてしまう。求める解が、小数点を含めて下の桁から見て trailing 0 を取り除いた最後の数字なので、N % 10 のみの計算をひたすら考えていけばよい…と思う、がジャッジをまだ通せていないので正答かどうか不明。
問題作成者である yuki2006 様に記事を見て頂いて以下のコードで無事 AC を頂きました。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll mod_pow(ll x, ll n, ll MOD) {
  if(n == 0) return 1;
  ll ret = mod_pow(x*x%MOD, n/2, MOD);
  if(n&1) (ret *= x) %= MOD;
  return ret;
}

int main() {
  
  ll N, M;
  cin >> N >> M;
  
  ll GCD = __gcd(N, M);
  N /= GCD, M /= GCD;
  
  if(M == 1) {
    while(N % 10 == 0 && N > 0) {
      N /= 10;
    }
    cout << N%10 << endl;
    return 0;
  }
  
  ll TWO = 0;
  ll FIVE = 0;
  while(M % 2 == 0) TWO ++, M /= 2;
  while(M % 5 == 0) FIVE ++, M /= 5;

  if(M != 1) {
    cout << -1 << endl;
    return 0;
  }
  
  N %= 10;
  
  if(TWO == FIVE) {
    cout << N << endl;
  }
  else {
    ll b = TWO < FIVE ? 2 : 5;
    cout << N * mod_pow(b, abs(TWO - FIVE), 10) % 10 << endl;
  }
  
  return 0;
}