AtCoder420 G
\(\color{black}{题目传送门}\)
题面
给你一个数字 \(X\),要你求出所有的 \(n\) 满足:\(\sqrt{n^2+n+X}\)是整数。并将所有满足要求的 \(n\) 从小到大排序后输出。
$-10^{14} \leq X \leq 10^{14} $
思路
首先\(\sqrt{n^2+n+X}\)是整数,就相当于\(n^2+n+X\)是平方数
分开讨论 \(X\) 为正数和为负数的情况
\(X\) 为正数
观察样例得到:\(n\)的负数解 \(=\) (\(-\)每个正数解) - 1
当 \(X\) 为正数,那么 \(n^2+n+X\) 显然是 $ > n^2$ 的一个平方数,为 $(n+k)^2 $ (\(k\)为正整数),
而 $(n+k)^2 = n^2 + 2nk + k^2 $
那么 \(X = (n^2 + 2nk + k^2) - (n^2 + n) = n \times (2k-1) + k^2\)
那么 \(n = \frac{(X - k^2)}{(2k-1)}\)
显然 \(1 \leq k^2 \leq X\) ,所以我们在\(\sqrt{X}\)的时间复杂度内可以枚举所有的 \(k\),对于每一个\(k\),如果 \(\frac{(X - k^2)}{(2k-1)}\) 不是非负整数,那么这个\(k\)不成立(\(n\)没有整数解),否则的话\(\frac{(X - k^2)}{(2k-1)}\)就是其中一个非负整数解,然后负数解就是(\(-\) 每个非负整数解) - 1
代码:
vector<long long> v; // 用于存储非负数解
for (int i = 1; 1ll * i * i <= x; i++) // 枚举k(我用的是i)注意:i*i 可能会爆int
{
double t = x - 1ll * i * i; // 先存一下
t /= (i * 2 - 1); // 得到 n
if (t == (long long)t) // 是整数
{
v.push_back(t); // 是个合法的非负整数解
}
}
cout << v.size() * 2 << endl; // 每一个非负整数解都有对应的负数解
// 由于x相同,所以:k越小,n越大,那么绝对值就越大。
for (long long i : v)
{
cout << (-i) - 1 << ' '; // 按照规律 输出负数解
}
reverse(v.begin(), v.end()); // 由于x相同,所以:k越小,n越大,因此我们需要大小转换一下。
for (long long i : v)
{
cout << i << ' '; // 输出正数解
}
cout << endl;
\(X\) 为负数
观察样例得到:\(n\)的负数解 \(=\) (\(-\)每个正数解) - \(1\) (和 \(X\)为正数一样)
为了方便,下文的\(X\)为输入的\(X\)的绝对值(算式的+-也会相应改)
首先由于\((n+1)^2 - n^2 = (n^2 + 2n + 1) - n^2 = 2n + 1\) 而 \(n - X\)显然小于 \(2n + 1\)所以 \((n^2+n-X)\)一定小于 \((n+1)^2\)
所以 \(n^2+n-X = (n-k)^2\) ( \(k\)为非负整数 )
而 $(n-k)^2 = n^2 - 2nk + k^2 $
那么 \(X = (n^2 + n) - (n^2 - 2nk + k^2) - (n^2 + n) = n \times (2k + 1) - k^2\)
那么 \(n = \frac{(X + k^2)}{(2k+1)}\)
显然 \(0 \leq k^2 \leq X\) ,所以我们在\(\sqrt{X}\)的时间复杂度内可以枚举所有的 \(k\),对于每一个\(k\),如果 \(\frac{(X + k^2)}{(2k+1)}\) 不是非负整数,那么这个\(k\)不成立(\(n\)没有整数解),否则的话\(\frac{(X + k^2)}{(2k+1)}\)就是其中一个非负整数解,然后负数解就是(\(-\) 每个非负整数解) - 1
代码:
vector<long long> v; // 暂存非负整数解
x = -x; // 负改正
for (int i = 0; 1ll * i * i <= x; i++) // 枚举k(我用的i)注意从0开始枚举而非从1开始。因为n^2+n-X可以等于n^2
{
double t = x + 1ll * i * i; // 先存一下 X+k^2
t /= (i * 2 + 1); // 除以i*2+1
if (t == (long long)t) // t是整数解
{
v.push_back(t); // 存下这个非负整数解
}
}
// 输出部分同 X为正数
cout << v.size() * 2 << endl;
for (long long i : v)
{
cout << (-i) - 1 << ' ';
}
reverse(v.begin(), v.end());
for (long long i : v)
{
cout << i << ' ';
}
cout << endl;
\(X = 0\)
直接输出即可,但是不要忘记特判他。
if (x == 0)
{
cout << 2 << endl << "-1 0 " <<endl; // 注意还有一个-1
return 0;
}
总代码:
高清代码附上:
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long x;
cin >> x;
// x非负
if (x >= 0)
{
// x = 0
if (x == 0)
{
cout << 2 << endl << "-1 0 " <<endl;
return 0;
}
// x为正数
vector<long long> v;
for (int i = 1; 1ll * i * i <= x; i++)
{
double t = x - 1ll * i * i;
t /= (i * 2 - 1);
if (t == (long long)t)
{
v.push_back(t);
}
}
cout << v.size() * 2 << endl;
for (long long i : v)
{
cout << (-i) - 1 << ' ';
}
reverse(v.begin(), v.end());
for (long long i : v)
{
cout << i << ' ';
}
cout << endl;
}
else // X为负数
{
vector<long long> v;
x = -x;
for (int i = 0; 1ll * i * i <= x; i++)
{
double t = x + 1ll * i * i;
t /= (i * 2 + 1);
if (t == (long long)t)
{
v.push_back(t);
}
}
cout << v.size() * 2 << endl;
for (long long i : v)
{
cout << (-i) - 1 << ' ';
}
reverse(v.begin(), v.end());
for (long long i : v)
{
cout << i << ' ';
}
cout << endl;
}
return 0;
}
完结撒花★,°:/$:.°★ 。
点个赞吧!

浙公网安备 33010602011771号