すごく教育的ないい問題な感じ
問題概要
整数 , が与えられる。
を満たす正の整数列 をすべて考えたときの、 の最大公約数の最大値を求めよ。
制約
考えたこと
候補を一気に絞る
まず の最大公約数が必ず の約数になることがわかる。まずはここの理解が難しいかもしれない。
- とする
- このとき はすべて の倍数である
- よって も の倍数である
- つまり は の約数である
こんな風に、「倍数」とか「約数」をコロコロ視点を入れ替えながら考察することがよくあるかもしれない。
あるいはこの事実を思い浮かべてもいいかも
整数 が与えられて、 の形で表される整数は の倍数のみである
は とすることで表される整数なので の倍数でなければならない。
詰める
ここまでで、 は の約数に絞られることがわかった。このうち最大を求めたい。あんまり大きいとダメなことがわかる。
- とすると、 なので である
ということがわかる。で、よく考えてみるとこれさえ満たしていれば、必ずそういう は作れることがわかる。
具体的には
- ...
とすればいい。
よってまとめると答えは「 の約数 のうち、 を満たす最大のものになる。
#include <iostream> #include <vector> #include <algorithm> using namespace std; // 約数列挙 vector<long long> calc_divisor(long long n) { vector<long long> res; for (long long i = 1LL; i*i <= n; ++i) { if (n % i == 0) { res.push_back(i); long long j = n / i; if (j != i) res.push_back(j); } } sort(res.begin(), res.end()); return res; } int main() { long long N, M; cin >> N >> M; vector<long long> div = calc_divisor(M); // M の約数 d であって、d * N <= M となる最大の d を求める long long res = 1; for (auto d : div) { if (d * N <= M) res = max(res, d); } cout << res << endl; }