トピック
ラグランジュの定理としても知られる4平方和の定理:
すべての正の整数は、最大4つの正の整数の2乗の合計として表すことができます。
0を含めると、4つの数値の2乗の合計として表すことができます。
例:
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
リソースの規則:
ピークメモリ消費
量<256MCPU消費量<3000ms
分析する
アルゴリズムの問題が発生した場合、より良い方法がない場合は、最初に暴力的な方法を考えてください。暴力的な方法でもポイントの一部を取得できます。繰り返しの場合、
この問題を最適化する暴力的な方法は次のとおりです。 aを列挙するには、b、c、dの範囲はルート番号nであり、時間計算量は約O(n ^ 2)です。質問で与えられたnの範囲は1e6であるため、最悪の場合は約1e12
です。 1.列挙
範囲の
縮小2.列挙変数
1の縮小は実行不可能であるため、列挙変数の縮小を検討できます。
最初に考えられるのは、dの列挙を省略することです。これは、Na abbccを使用して表すことができます。 d、最悪の場合はおそらく1e9に減少し、タイムアウトにもなります。
次にcとdを省略し、 naabbを格納してcc + d dを表しますが、現時点ではcとdはであるため、この値は次のようになります。cまたはdの値とバインドするには、ハッシュテーブルを使用してc c + b bとcをバインドし、必要に応じて、この値をccから直接減算します。次に、それを二乗して取得します
。この時点では、最後の2つの要素を列挙し、すべての組み合わせをマップに格納してから、aとbを列挙し、マップでna ab bを見つけ、見つかった場合はcを直接割り当て、次にdを計算すると、答えが見つかります。ここでのループは字句の順序に従う必要があり、答えに一致する最初のループが答えです。
フルACコード
#include <bits/stdc++.h>
using namespace std;
map<int,int>cache;
int main (void)
{
int n;
cin>>n;
for(int c=0;c*c<=n/2;c++) //存储后两个数字的平方和
for(int d=c;d*d+c*c<=n;d++)
{
if(cache.find(c*c+d*d)==cache.end())
cache[c*c+d*d]=c;
}
for(int a=0;a*a<=n/4;a++) //循环遍历前两个数字
for(int b=a;a*a+b*b<=n/2;b++)
{
if(cache.find(n-a*a-b*b)!=cache.end())
{
int c=cache[n-a*a-b*b];
int d=sqrt(n-a*a-b*b-c*c);
printf("%d %d %d %d",a,b,c,d);
return 0;
}
}
return 0;
}
要約する
ループの時間計算量は約O(n)です。マップの検索時間計算量は約O(logn)であるため、ここの評価データは合格できます。