Codeforces Round 218(Div.2 Only) B Fox Dividing Cheese
問題
サイズがa,bの2つのチーズがあって、2匹の熊がでかい方を取り合おうとしていると、キツネさんがやってきます。
「私が2つのチーズのサイズを同じにしてみせます。」
どうやるんだよ、と熊は不思議そうです。
「2で割れるサイズだったら半分私が食べることができ、
3で割れるサイズだったら2/3を私が食べることができ、
5で割れるサイズだったら4/5を私が食べることができます。
これを繰り返して、そのうち2つのチーズのサイズを同じにすることができます。」
熊はこの提案に「ただし最少ステップ数でサイズを等しくしろ」という条件付きで乗っかりました。
キツネがチーズを食べる最少の回数(どうやっても等しくできないなら-1)を出力しなさい。
制約
1≦a,b≦10^9
解法
結論から書くと、
a,bの最大公約数(gcd(a,b))までチーズを小さくするのが最速で、
a/gcd(a,b)、b/gcd(a,b)が2,3,5以外の素因数を含んでいたら-1です。
各操作ではチーズは1/2, 1/3, 1/5されるので、サイズが等しくなるということはa,bの公約数のいずれかに落ちるということになりますが、
全ての公約数は最大公約数の約数なので(素因数分解を考えれば明らかだと思います)、
a/gcd(a,b)、b/gcd(a,b)が2,3,5以外の素因数を含んでいたら、公約数のどこにも落ちることができません。
逆に含んでいなかった場合は最大公約数に落とすことが可能になり、これが最少ステップでサイズを一致させる解となります。
プログラム
#include<iostream> #include <fstream> #include <stdio.h> #include <stdlib.h> #define _USE_MATH_DEFINES #include <math.h> #include<string> #include<vector> #include<cmath> #include<stack> #include<queue> #include<sstream> #include<algorithm> #include<map> #include<complex> #include<ctime> #include<set> using namespace std; #define li long long int #define rep(i,to) for(li i=0;i<((li)(to));i++) #define repp(i,start,to) for(li i=(li)(start);i<((li)(to));i++) #define pb push_back #define sz(v) ((li)(v).size()) #define bgn(v) ((v).begin()) #define eend(v) ((v).end()) #define allof(v) (v).begin(), (v).end() #define dodp(v,n) memset(v,(li)n,sizeof(v)) #define bit(n) (1ll<<(li)(n)) #define mp(a,b) make_pair(a,b) #define rin rep(i,n) #define EPS 1e-10 #define ETOL 1e-8 #define MOD 100000000 #define F first #define S second #define p2(a,b) cout<<a<<"\t"<<b<<endl #define p3(a,b,c) cout<<a<<"\t"<<b<<"\t"<<c<<endl li gcd(li a, li b){ if(a<b)swap(a,b); if(a%b==0)return b; return gcd(b, a%b); } li count(li x){ li res=0; while(x%2==0){ x/=2; res++; } while(x%3==0){ x/=3; res++; } while(x%5==0){ x/=5; res++; } if(x>1)return -1; return res; } int main(){ li a,b; cin>>a>>b; li ab=gcd(a,b); li aa,bb; aa=a/ab; bb=b/ab; li ca,cb; ca=count(aa); cb=count(bb); if(ca<0||cb<0)cout<<-1<<endl; else cout<<ca+cb<<endl; return 0; }