122.四平方和(暴力枚举)

122. 四平方和(暴力枚举)

2016年蓝桥杯省赛 - 四平方和(困难)

标签:2016 省赛 暴力枚举

题目描述

四平方和定理,又称拉格朗日定理:每个正整数都可以表示为至多 4 个正整数的平方和。把 0 也算进去,就正好可以表示为 4 个数的平方和,比如

5=02+02+12+22 5 = 0^2 + 0^2 + 1^2 + 2^2 5=02+02+12+22

7=12+12+12+22 7 = 1^2 + 1^2 + 1^2 + 2^2 7=12+12+12+22

一个正整数可能存在多种表示法。要求把 4 个数排序为 0≤a≤b≤c≤d0 \le a \le b \le c \le d0≤a≤b≤c≤d,并把所有表示法按 a,b,c,da, b, c, da,b,c,d 为联合主键升序排列,输出排在最前面的那一组。

输入描述

一个正整数 NNN(N<5000000N < 5000000N<5000000)。

输出描述

4 个非负整数,按从小到大排序,中间用空格分开。

输入输出样例

示例 1:

输入

txt 复制代码
5

输出

txt 复制代码
0 0 1 2

示例 2:

输入

txt 复制代码
12

输出

txt 复制代码
0 2 2 2

示例 3:

输入

txt 复制代码
773535

输出

txt 复制代码
1 1 267 838

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

解题思路

四个数要满足 a2+b2+c2+d2=Na^2 + b^2 + c^2 + d^2 = Na2+b2+c2+d2=N,并且 0≤a≤b≤c≤d0 \le a \le b \le c \le d0≤a≤b≤c≤d,输出字典序最小的那一组。

直接四重循环枚举四个数太慢,但注意到:只要 a,b,ca, b, ca,b,c 定了,ddd 也就定了------剩下的部分必须是一个完全平方数。所以先算出

d=⌊N−a2−b2−c2⌋ d = \left\lfloor \sqrt{N - a^2 - b^2 - c^2} \right\rfloor d=⌊N−a2−b2−c2 ⌋

再回头验证 a2+b2+c2+d2=Na^2 + b^2 + c^2 + d^2 = Na2+b2+c2+d2=N 就行。这样四重循环直接降成三重。

把 NNN 看成一条长条就是:a2a^2a2、b2b^2b2、c2c^2c2 之外剩下的那截,必须正好等于 d2d^2d2,否则这组 (a,b,c)(a,b,c)(a,b,c) 作废:

枚举时每一层都从上一个数开始(b≥ab \ge ab≥a、c≥bc \ge bc≥b、d≥cd \ge cd≥c),顺序既不重复也不遗漏;同时用 ⋅\sqrt{\cdot}⋅ 收紧每层的上界,比如给定 aaa 后 bbb 最多取到 N−a2\sqrt{N - a^2}N−a2 ,可以省掉大量不可能的取值。

又因为 a,b,c,da, b, c, da,b,c,d 是从小到大一层层枚举的,第一组满足等式的解,恰好就是按 a,b,c,da, b, c, da,b,c,d 升序排在最前面的那组,找到直接返回即可。

以样例 773535 走一遍:

txt 复制代码
N = 773535

a=0            整个分支试遍,无解
a=1, b=1
  c=1 ... 266    剩余部分都不是完全平方数
  c=267        剩余 = 773535 - 1 - 1 - 267² = 702244
               d = √702244 = 838,且 838 ≥ 267
               → 输出 1 1 267 838

代码实现

python 复制代码
import math


def hs(n):
    am = int(math.sqrt(n))  # a 最大值

    for a in range(am + 1):
        bm = int(math.sqrt(n - a * a))  # 给定a后,b的最大值

        for b in range(a, bm + 1):  # 保证 a <= b
            cm = int(math.sqrt(n - a * a - b * b))  # 给定a和b后,c的最大值

            for c in range(b, cm + 1):  # 保证 b <= c
                t = n - a * a - b * b - c * c  # 剩下的部分应等于 d^2
                d = int(math.sqrt(t))  # 计算d
                if d >= c and a * a + b * b + c * c + d * d == n:
                    return a, b, c, d


n = int(input())

print(' '.join([str(x) for x in hs(n)]))

复杂度分析

  • 时间复杂度 :O(N3/2)O(N^{3/2})O(N3/2),三层枚举 a,b,ca, b, ca,b,c,每层的上界都是 N\sqrt{N}N 级别;找到第一组解就返回,实际往往远小于这个上界。
  • 空间复杂度 :O(1)O(1)O(1),只用了几个循环变量和临时变量。
相关推荐
倒头就睡的小比特1 小时前
贪心算法介绍
算法·贪心算法
鱼宵1 小时前
工厂模式实战:消灭魔法数字,把写死的 new 收进一个厂里
开发语言·python
deepseek231 小时前
GitHub 停发 push 邮件后,自动通知怎么接?用 Python 做验签、去重与可靠入队
python·github·webhook
万少2 小时前
Qoder sonus模型 20分钟,复刻 马斯克 飞天汽车
前端·后端·算法
昔我往昔2 小时前
chromadb 这个query_texts 查询的是基于分词还是基于向量查询的
python·chromadb
鸿业远图科技2 小时前
抚顺市_公交站点
python
VidDown2 小时前
上线三个月后的第一次事故:一个 Django 服务的日志、监控与故障复盘
数据库·python·django·wpf·音视频·视频编解码
七牛云行业应用2 小时前
Muse Spark Open 发布:Meta 称其为美国最强开放权重模型,816B 参数如何落地
算法
esop轻Mes看板亮灯分拣ESD静电安2 小时前
产线“最后一米”的破局密码:ESOP与MES的区别与深度协同
算法