G - sqrt(n²+n+X) Editorial
by
MMNMM
\(n\) が条件を満たすなら \(-n-1\) も条件を満たすことから、\(n\ge0\) の条件を課した解を列挙すればよいです。
整数 \(k\) について \(\sqrt{n ^ 2+n+X}=n+k\) が成り立っているとして式を整理します。 \(n+k\ge0\) かつ \(n ^ 2+n+X=n ^ 2+2kn+k ^ 2\) となって、第 \(2\) 式を \(n\) について解くと \(n=\dfrac{X-k ^ 2}{2k-1}\) となります。
\(n\ge0,n+k\ge0\) より \(n(n+k)(2k-1) ^ 2\ge0\) となるので、\((X-k ^ 2)(X+k(k-1))\ge0\) を得ます。
- \(X\gt0\) のとき、\(X+k(k-1)\gt0\) なので \(X-k ^ 2\ge0\) でなければならず、\(-\sqrt X\le k\le\sqrt X\) が必要です。
- \(X\lt0\) のとき、\(X-k ^ 2\lt0\) なので \(X+k(k-1)\le0\) でなければならず、\(\dfrac{1-\sqrt{1-4X}}2\le k\le\dfrac{1+\sqrt{1-4X}}2\) が必要です。
- \(X=0\) のとき、\(-k ^ 3(k-1)\ge0\) より、\(k=0,1\) が必要です。
以上より、\(-\sqrt{|X|}\le k\le1+\sqrt{|X|}\) の範囲を探索すれば十分であることがわかります。
よって、この範囲の \(k\) に対して \(\dfrac{X-k ^ 2}{2k-1}\) が条件を満たすか判定すればこの問題を解くことができます。
実装例は以下のようになります。
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
int main(){
using namespace std;
long X;
cin >> X;
// 探索する k の範囲
// abs(X) は double で正確に表現できるので、この平方根の小数点以下を切り捨てた値も正確に得られる
long bound = sqrt(abs(X)) + 1;
vector<long> ans;
for (long k{-bound + 1}; k <= bound; ++k)
if ((X - k * k) % (2 * k - 1) == 0) { // 割り切れることが必要
// n ≧ 0 かつ n + k ≧ 0 なら OK
auto n = (X - k * k) / (2 * k - 1);
if (n >= 0 && n + k >= 0) {
ans.emplace_back(n);
ans.emplace_back(-n - 1);
}
}
ranges::sort(ans);
cout << size(ans) << endl;
for (const auto n : ans)
cout << n << endl;
return 0;
}
posted:
last update:
