题目 | Many Perfect Squares
Codeforces Round #844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round)
D. Many Perfect Squares
https://codeforces.com/contest/1782/problem/D
4 seconds / 512 megabytes
standard input / standard output
Problem
You are given a set $a_1, a_2, \ldots, a_n$ of distinct positive integers.
We define the squareness of an integer $x$ as the number of perfect squares among the numbers $a_1 + x, a_2 + x, \ldots, a_n + x$.
Find the maximum squareness among all integers $x$ between $0$ and $10^{18}$, inclusive.
Perfect squares are integers of the form $t^2$, where $t$ is a non-negative integer. The smallest perfect squares are $0, 1, 4, 9, 16, \ldots$.
Input
Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1 \le t \le 50$). The description of the test cases follows.
The first line of each test case contains a single integer $n$ ($1 \le n \le 50$) — the size of the set.
The second line contains $n$ distinct integers $a_1, a_2, \ldots, a_n$ in increasing order ($1 \le a_1 < a_2 < \ldots < a_n \le 10^9$) — the set itself.
It is guaranteed that the sum of $n$ over all test cases does not exceed $50$.
Output
For each test case, print a single integer — the largest possible number of perfect squares among $a_1 + x, a_2 + x, \ldots, a_n + x$, for some $0 \le x \le 10^{18}$.
Example
Input
4
5
1 2 3 4 5
5
1 6 13 22 97
1
100
5
2 5 10 17 26
Output
2
5
1
2
Note
In the first test case, for $x = 0$ the set contains two perfect squares: $1$ and $4$. It is impossible to obtain more than two perfect squares.
In the second test case, for $x = 3$ the set looks like $4, 9, 16, 25, 100$, that is, all its elements are perfect squares.
题解
核心思路
首先,$x$ 可能的取值有 $10^{18}$ 种,这个数据规模过于庞大。如果能减小这个规模到合适的大小,我们遍历所有可能的 $x$,找到符合条件最大的就行了。
减小 $x$ 的规模
首先我们可以确定的是,答案最小为 $1$,因为单个数可以放缩到任意完全平方数。
我们继续判断答案是否 $\geq2$:取任意 $i,j$($1\leq i<j\leq n$),判断是否存在 $x$,使 $a_i+x,a_j+x$ 均为完全平方数。若存在,则代表答案 $\geq2$,具体的值遍历 $a_i+x$ 求得;若不存在,则说明答案 $<2$,即答案为 $1$. 最后求得所有答案的最大值即可。
由于最多有 $\frac{n(n-1)}{2}$ 种取法,因此 $x$ 的数量级大约为 $n^2$(下文会做补充),数据规模瞬间从 $10^{18}$ 下降到了 $10^3$.
给定一对数如何求解 $x$
该问题的形式化表述为:取任意 $i,j$($1\leq i<j\leq n$),求解:
$$ \begin{cases} a_i+x=u^2\\ a_j+x=v^2 \end{cases} $$
三个未知数 $x,u,v$ 两个方程,很明显是无穷解的。但是我们要求的是整数解,那么解的数量就有限了。下面是解法:
$$ \begin{align} 两式相减&\Rightarrow a_i-a_j=u^2-v^2\\ &\Rightarrow a_i-a_j=(u+v)(u-v)\\ \end{align} $$
为了简洁,令 $t:=a_i-a_j$,得到:
$$ t=(u+v)(u-v) $$
将 $t$ 分为两个因子 $p,q$,即 $t=pq$,得到:
$$ pq=(u+v)(u-v) $$
若 $q-p$ 为偶数,则可以构造得到解如下:(如果为奇数则这种分解方式无解)
$$ \begin{cases} \displaystyle{u=\frac{q-p}{2}}\\\\ \displaystyle{v=\frac{q+p}{2}} \end{cases} $$
回代 $u$,将 $x$ 计算出来:
$$ x=u^2-a_i $$
若 $x\geq0$,则符合条件,遍历 $a_i+x$,计算出多少个为完全平方数。(若 $<0$ 则说明这种情况不符合条件)
时间复杂度
最多 $\frac{n(n-1)}{2}$ 种取法,数量级为 $n^2$
$x$ 的正因子个数为 $d(x)$,这个数值无法用表达式直接确定,但可以查表确定最大值为 $1344$.
$n\leq$ | $\max\{\omega(n)\}$ | $\max\{d(n)\}$ | $n\leq$ | $\max\{\omega(n)\}$ | $\max\{d(n)\}$ |
---|---|---|---|---|---|
$10^1$ | $2$ | $4$ | $10^9$ | $9$ | $1344$ |
$10^2$ | $3$ | $12$ | $10^{10}$ | $10$ | $2304$ |
$10^3$ | $4$ | $32$ | $10^{11}$ | $10$ | $4032$ |
$10^4$ | $5$ | $64$ | $10^{12}$ | $11$ | $6720$ |
$10^5$ | $6$ | $128$ | $10^{13}$ | $12$ | $10752$ |
$10^6$ | $7$ | $240$ | $10^{14}$ | $12$ | $17280$ |
$10^7$ | $8$ | $448$ | $10^{15}$ | $13$ | $26880$ |
$10^8$ | $8$ | $768$ | $10^{16}$ | $13$ | $41472$ |
$10^9$ | $9$ | $1344$ | $10^{17}$ | $14$ | $64512$ |
$10^{10}$ | $10$ | $2304$ | $10^{18}$ | $15$ | $103680$ |
通过遍历确定答案,数量级为 $n$
综上,时间复杂度勉强写成:$O(n^3\cdot\underset{1\leq i<j\leq n}\max\{d(a_j-a_i)\})$
用 $d(n)\approx\sqrt[3]{n}$ 来近似一下,那么如果是最坏情况可以达到 $10^8$ 规模,有可能超时(但实际上不会,运行时间离时限还很远)
由于正因子个数的无法直接计算,而且对于一个正因子,也不一定有解,所以这个时间复杂度没办法准确表述,实际情况应该远小于上述复杂度。
代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
bool is_square(int n)
{
int r = sqrt(1.0L * n);
return r * r == n;
}
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
int ans = 1;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
int t = a[j] - a[i];
for (int p = 1; p * p <= t; p++)
{
if (t % p)
continue;
int q = t / p;
if ((q - p) % 2)
continue;
int u = (q - p) / 2, v = (q + p) / 2;
int x = u * u - a[i];
if (x < 0)
continue;
int res = 0;
for (int ii = 0; ii < n; ii++)
if (is_square(a[ii] + x))
res++;
ans = max(ans, res);
}
}
}
cout << ans << endl;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi