第七届蓝桥杯JavaB组-四平方和

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

比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开

例如,输入:
5
则程序应该输出:
0 0 1 2

再例如,输入:
12
则程序应该输出:
0 2 2 2

再例如,输入:
773535
则程序应该输出:
1 1 267 838

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 3000ms



import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main{
    public static long []temp = new long[4];
    public static long []ans = new long[4];
/**
 * 存储按照升序排列的第一个答案;逻辑上筛选的规则是:如果ans小于temp中的,表示ans中存储的就是满足条件的,直接return;
 * 如果ans大于temp则temp中存储的才是最适合的,则交换。
 * 如果相等则进行下一次比较;
 * */
    public static void saveAns(boolean flag){
        //如果是第一个temp直接赋值给ans即可
        if(flag) { for(int j = 0; j < temp.length; ++j) ans[j] = temp[j]; }
        for(int i = 0; i < 4; ++i) {
            if(ans[i] < temp[i]) return;
            else if(ans[i] > temp[i]) { for(int j = 0; j < temp.length; ++j) ans[j] = temp[j]; return; }
        }
    }
/**
 * 总的思路是:
 * 从这个数num的开根号后得到的数num_sqrt开始遍历:
 * 比如:num = 18, i = num_sqrt = 4;
 * 4 * 4 = 16,小于18则存储4,num-16后还剩2,故只需从4遍历到0,看那个数的平方不会超过2即可;
 * 4 * 4 = 16,大于2,进行下一次
 * 3 * 3 = 9,大于2,进行下一次
 * 2 * 2 = 4, 大于2,进行下一次
 * 1 * 1 = 1,小于2,num - 1 = 1, 此时还要继续判断1是否满足,1 * 1 = 1,小于等于1,num - 1 = 0;
 * 此时再调用saveAns()判断该temp中的解是不是需要的解。
 *
 * 然后i--, i = 3;
 * 3 * 3 = 9, 小于18,存储3,num - 9 = 9,继续判断3 * 3 = 9, 9 - 9 = 0,就会跳出while,调用saveAns()方法。
 *
 * 思路就是从后向前遍历,先看最大的是否满足,不满足就找下一个,满足就存到temp中。
 *
 * 看不懂我写的文字的话,可以自己在纸上把这个测试用例跑一下!
 * 如果那里有错的话,或者改进的地方请大家在留言区留言。THANKS
 * */
    public static void main(String[] args) throws Exception{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        long num = Long.parseLong(in.readLine());
        in.close();
        boolean flag = true;
        Arrays.fill(ans, 0L);
        long renum = 0, num_sqrt = (long)Math.sqrt(num);

        for(long i = num_sqrt; i >= 0; --i) {
            if(num == i * i) { ans[3] = i; break; }
            Arrays.fill(temp, 0L);
            renum = num;
            int temp_pos = 3;
            for(long j = i; temp_pos >=0 && j >= 0; --j) {
                while(temp_pos >= 0 && renum !=0 && (renum - j * j) >= 0) {
                    renum -= j * j;
                    temp[temp_pos--] = j;
                }
                if(0 == renum) { saveAns(flag); if(flag) flag = false; break; }
            }
        }
        for(int i = 0; i < ans.length; ++i)
            if(i == ans.length - 1) System.out.println(ans[i]);
            else System.out.print(ans[i] + " ");
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值