1. 程式人生 > >第七屆藍橋杯JavaB組-四平方和

第七屆藍橋杯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] + " ");
    }
}