1 条题解
-
1
说句闲话: 出题人这题做了半年。
Part 0
显然,无解是不可能的,因为 个 的和就是 ,而 ,因此这一定是合法的方案。
Part 1
设答案为 ,求证:,其中 。
证明:
-
先证明 :
若 ,则 。
显然 ,因此 。
于是,,即 。
由于每个完全平方数都不大于 ,因此 个完全平方数的和最大只能是 。
然而,,因此, 个完全平方数的和绝不可能等于 ,矛盾。
综上, 的假设不成立,因此 ,得证。
-
再证明 :
设 。
显然 ,因此 ,于是 。
根据这个定理,总有四个非负整数 ,使得 。
由于 ,而 均非负,因此 均不大于 ,满足「不大于 」的要求。
将 代入,得 。
此时,等式右边共 个完全平方数,故 (为 的项可以删去,因此可能少于 个),得证。
综上所述,,原命题得证。
显然,由于 , 的取值只有 种(,,,,)。因此,考虑暴力枚举 的值,每次判断是否可行(若 则直接跳过,保证 )。
Part 2
先来考虑一种错误的解法():按照与加强前的原题中 解法类似的思路,使用完全背包求解,时间复杂度 ,超时。
显然,使得上述算法超时的主要原因是状态太多(对应 中的 )。要想优化此算法,必须减少状态数。
由于正向求解遇到了困难,考虑反向求解:每次枚举 的值时,先假设所有的完全平方数都是 ,再把一部分 修改为其它小于 的完全平方数,使总和减小(倒扣),反向求解。
于是,完全背包的定义发生了转变。
Part 3
定义 为:当 时,恰好倒扣 至少需要修改的 的个数,若无法恰好倒扣 则其值为 。()
初始状态:
- (解释:前者无需倒扣,后者假定无法恰好倒扣,等待更新。)
状态转移方程(顺序:按 升序):
- 其中 ,保证
- (解释:修改 个 (改为 ),倒扣 。)
由于需要从 倒扣至 ,共倒扣了 ,因此 即为所需的答案。
注意:若 ,则表明没有足够的 用于倒扣时的修改(或根本不可能恰好倒扣,此时 ),该 的值必须舍去。
Part 4
求证:倒扣的总量(,即当 时下标 的上界)不大于 。
证明:
前面已经证明 。
-
当 时:
此时有 ,因此 ,即 。
又因为前面已经证明 ,因此 。
于是 $k \cdot m^2 \le (p+4) \cdot m^2 \le n+4 \cdot m^2-1$,即 。
由此可得 。
-
当 时:
显然此时 。该等式右边共 个完全平方数,故 (前面已经证明 )。
将上面两个等式代入计算,得 。显然 。
综上所述,,原命题得证。
若 ,求证:。
证明:
根据上文,模拟可得,过程略去。原命题得证。Part 5
最终,时间复杂度 ,空间复杂度 ,可以通过此题。
Part 6
std:
#include <bits/stdc++.h> using namespace std; const int M = 100 + 5; vector <char> w[M]; int main() { for (int i = 1; i <= 100; i ++) { w[i].resize(4 * i * i + 5); w[i][0] = 0; for (int j = 1; j <= 4 * i * i - 1; j ++) { w[i][j] = 27; for (int x = i - 1; x >= 1; x --) if (j - (i * i - x * x) >= 0) w[i][j] = min(w[i][j], (char) (w[i][j - (i * i - x * x)] + 1)); } } int Q; scanf("%d", &Q); while (Q --) { long long n; int m; scanf("%lld %d", &n, &m); long long k = n / (m * m); while (k * m * m < n || w[m][k * m * m - n] == 27 || w[m][k * m * m - n] > k) k ++; printf("%lld\n", k); } return 0; }
-
- 1
信息
- ID
- 3
- 时间
- 1750ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 15
- 已通过
- 5
- 上传者