2016第七屆藍橋杯C++B組第八題:四平方和
阿新 • • 發佈:2019-02-12
題目:
四平方和
四平方和定理,又稱為拉格朗日定理:
每個正整數都可以表示為至多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
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
思路:用陣列sum[i]存i的平方(5000000的1/2次方為2236,所以陣列只需開2237即可),先找到比輸入資料x大的前一個位置xi, 遍歷f(xi)到f(1)(f函式從xi開始向前貪心獲取比當前x小的數的1/2次方,得到一組合法的an),將an轉化為對應字串放入set中自動升序排序,最後輸入set中的第一個元素。
程式碼:
// 四平方和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2237;
ll sum[N+1]; // √5000000 = 2236+
ll an[4]={0,0,0,0};
// 返回平方大於x的前一個位置
int getpos(ll x)
{
for(int i=0;i<=N;++i) {
if(sum[i]>=x) return i-1;
}
return -1;
}
// 將陣列轉化為相應字元組成的字串, 字元間用空格隔開
string a2s()
{
ostringstream ostr;
for(int i=0;i<4;++i) ostr << an[i] << " ";
return ostr.str();
}
// 根據xi提供一組an (合法則返回true)
bool f(ll x,int xi)
{
memset(an,0,sizeof(int)*4);
int i=3;
while(i>=0&&x>0) {
for(int j=xi;j>0;--j) {
if(x==sum[j]) {
an[i] = j;
x=0;
--i;
break;
} else if(x>sum[j]) {
while(x>=sum[j]&&i>=0&&x>0) {
an[i]=j;
x-= sum[j];
--i;
}
}
}
}
if(x>0) return false;
return true;
}
set<string> sset;
int main()
{
for(int i=0;i<=N;++i) sum[i] = i*i;
ll x;
cin >> x;
int xi = getpos(x);
while(xi>0) {
if(f(x,xi)) sset.insert(a2s());
--xi;
}
// 第一個元素即是最終結果
set<string>::iterator it = sset.begin();
string res = *it;
cout << *it << endl;
return 0;
}