SRM 375 250pt: DivisibleByDigits
問題概要
整数n(<10^9)が与えられる。nがprefixになるような数のうち、nの各桁の数字(0以外)で割りきれるような最小のものを返す問題。
考えたこと
- とりあえずLCMが必要なことは分かる。
- LCMが分かれば後はnがprefixになるような数字の上限と下限の間にLCMの倍数があるか判定すれば良い。
- sup/LCM > inf/LCMならばその間にLCMの倍数が存在するので、それを真面目に実装する。
- 合わない。何で?
- 問題文読み間違えてた。答えはnの倍数でもある必要があると思っていたけど、そうじゃないらしい。
- 修正。Accept。
practiceで通ったコード
計算量O(log N)くらい。
#include <algorithm> using namespace std; typedef long long int64; int64 lcm(int64 a, int64 b){ return a/__gcd(a,b)*b; } struct DivisibleByDigits { int64 getContinuation(const int64 n) { int64 A = 1; for(int64 m=n; m>0; m/=10){ int64 last_dig = m%10; if(last_dig){ A = lcm(A, last_dig); } } if(n%A==0){ return n; } for(int64 d=10;;d*=10){ int64 lb = n*d, ub = (n+1)*d-1; if(lb%A==0){ return lb; } if(lb/A < ub/A){ return ((lb+A-1)/A)*A; } } return -1; } };
他の人の解法
りんごさんの解法が相変わらずシンプルだった。答えはn*10^d + iの形になるけど、LCM(1..9)が4桁程度なので、dの値は高々5程度。なので単純に全探索すれば良い。
#include <vector> using namespace std; typedef long long int64; vector<int> digs; struct DivisibleByDigits { int64 getContinuation(const int64 n) { for(int64 m=n; m; m/=10){ int dig = m%10; if(dig){ digs.push_back(dig); } } for(int d=0, base=1; d<5; d++, base *= 10){ for(int i=0; i<base; i++){ if(check(n*base + i)){ return n*base + i; } } } return -1; } bool check(int64 x){ for(int i=0; i<(int)digs.size(); i++){ if(x%digs[i]){ return false; } } return true; } };