Uva-11300分金币

这道题就是一道数学推理题一个人接收左右金币可以分为俩个状态,一个收,一个接如图所示:


每个人最终的状态就是ave = sum / n个金币,就是求平均值

每个人开始的状态是有金币y[i]个所以可以求得一个方程:

y[1] - x[1] + x[2] = ave;

y[2] - x[2] + x[3] = ave;

一直到y[n - 1] - x[n - 1] + x[n] = ave;

为什么到n-1就结束因为我们要根据已知信息推出未知信息,而第n个人的所有信息由x[1]和x[n- 1]已经推出所以没有必要

x[2] = ave - y[1] + x[1]   设给出的金币为c[1] = y[1] - ave;

x[2] = x[1] - c[1];

x[3] = ave - y[2] + x[2]

x[3] = ave - y[2] + x[1] +y[1] - ave;

x[3] = 2 *ave - y[2] +y[1] + x[1];

c[2] = y[2] - ave  + c[1];

x[3] = x1 - c[2],以此类推:

最后转化成|x[1]| + |x[1] - c[1]|......;

于是转移的最短金币就是求一个点到各个点的距离之和最短,所以中位数到各个点的距离之和最短.

代码如下 :

# include <iostream>
# include <numeric>
# include <algorithm>
# include <functional>
# include <list>
# include <map>
# include <set>
# include <stack>
# include <deque>
# include <queue>
# include <vector>
# include <ctime>
# include <cstdlib>
# include <cmath>
# include <string>
# include <cstring>
# include <iomanip>

using namespace std;

//推导公式就可以
const int maxn = 1000001;

long long int A[maxn];
long long int C[maxn],n;
int main(int argc, char *argv[])
{
	
	while(scanf("%lld", &n) != EOF)
	{
		memset(A, 0 , sizeof(A));
		memset(C, 0 , sizeof(C));
		A[0] = C[0] = 0;
		long long int sum = 0, m = 0;
		for(int i = 1; i <= n; i++)
		{
			scanf("%lld", &A[i]);
			sum += A[i];
		}
		
		m = sum / n;
	
		for(int i = 1; i < n; i++)
		{
			C[i] = C[i - 1] + A[i] - m;
		}
		sort(C , C + n);
		//从 0 开始
		long long x1  = C[n / 2] , ans = 0;//求x1中位数

		for(int i = 0; i < n; i++)
		{
			ans += abs(x1 - C[i]);
		}
		printf("%lld\n", ans);
	}
    return 0;
}


猜你喜欢

转载自blog.csdn.net/i_o_fly/article/details/81005439
今日推荐