(暴力+ハッシュテーブルの最適化)Blue Bridge Cup 2016C \ C++A州大会Zhenti8SquareSum

トピック

ラグランジュの定理としても知られる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)であるため、ここの評価データは合格できます。

おすすめ

転載: blog.csdn.net/weixin_46035615/article/details/123925307