効率的な表現のためにインスピレーションを与えるコードを少なくします。
思考分析
質問の意味:n個の数値が与えられた場合、シーケンス内の数値を等しくするために少なくともいくつかの操作を求めます。
操作1:シーケンスの任意の数から1を減算します。
操作2:シーケンスの任意の数から1を引きます。1を任意の数に追加します(1過去の移動に相当)
質問の数が最も少ない質問は貪欲である必要がありますが、もちろんこの質問はもう少し考えたものであり、純粋に貪欲だと非常に面倒になります。
最初に平均nを見つけます
最初のアイデアは、数値> nのオーバーフロー値を数値<nに移動することでした。最後に、余分な数を直接減算します。
このアイデアは実現可能ですが、最適なソリューションではありません。
最終的な目標について考えてみましょう。最終値は同じである必要があるため、次のように簡略化できます。数値のオーバーフロー部分> nを累積し、累積された合計を出力します。足し算と引き算は相対的であるため、操作の数> nのみが必要であり、部分<nは自然に処理されます(ゲーム理論と同様に、相対的な状況のみが考慮されます)。
最適化前のコード(時間がかかる800ミリ秒):
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main() {
ios::sync_with_stdio(false);
int T; cin>>T; while(T--) {
long long n, sum = 0; cin>>n;
for(int i = 0; i < n; i++) {
cin>>a[i]; sum+=a[i]; }
long long sum1=0, sum2=0;
sum /= n;
for(int i = 0; i < n; i++)
if(a[i] > sum) sum1 += a[i]-sum;
else sum2 += fabs(sum-a[i]);
cout << (long long)(min(sum1,sum2)+fabs(sum1-sum2)) << endl;
}
return 0; }
注:コードの16行目では、変数を操作すると、その値の範囲がint行の変数の範囲に変更されるため、強化する必要があります。そうしないと、オーバーフローします。
最適化されたコード(時間がかかる160ミリ秒)
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main() {
ios::sync_with_stdio(false);
int T; cin>>T; while(T--) {
long long n, sum = 0; cin>>n;
for(int i = 0; i < n; i++) {
cin>>a[i]; sum+=a[i]; }
long long sum1=0;
sum /= n;
for(int i = 0; i < n; i++)
if(a[i] > sum) sum1 += a[i]-sum;
cout << (long long)(sum1) << endl;
}
return 0; }