15行代码AC——ZOJ - 4118 Stones in the Bucket(思维题+优化方案)(第十届山东省ACM程序设计竞赛F题)

励志用少的代码做高效表达。


思路分析

题意:给定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; } 

猜你喜欢

转载自blog.csdn.net/weixin_43899069/article/details/108305944
今日推荐