励志用少的代码做高效表达。
思路分析
题意:给定n个数,问最少操作几次,使数列中的数全部相等。
操作一:将数列中任意数减一。
操作二:将数列中任意数减一。任意数加一(相当于把1挪过去)
涉及到最少的题,一定就是贪心了, 当然,本题考思维多一点,如果只是单纯的贪,会很麻烦。
首先求出平均数n
最开始的思路是:将>n的数的溢出值,挪给<n的数。 最后将多出来的数直接减掉。
思路可行, 但这不是最优化的解法。
想一想我们最终的目的:要求最后的值一样,因此可以这样简化:对>n的数的溢出部分累加, 输出累加和即可。 因为相加和相减是相对的,只要求出了>n要操作的次数, <n的部分自然就处理掉了(只考虑相对的情况,类似博弈论)。
优化前的代码(耗时800ms):
#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行变量的范围,需加强转,否则溢出。
优化后的代码(耗时160ms)
#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; }