C实践习题集2之均等笔

均等笔

n个人围成一圈,每人有ai支笔。每人可以向左右相邻的人传递笔,每人每次传递一支笔消耗的能量为1。求使所有人获得均等数量的笔的最小能量。

输入格式:

第一行一个整数n ,表示人的个数(30%的数据,n<=1000;100%的数据,n<=1e6)。

接下来n行,每行一个整数 ai。

输出格式:

输出一个整数,表示使所有人获得均等笔的最小能量。(答案保证可以用64位有符号整数存储)

输入样例:

4
1
2
5
4

输出样例:

4

算法说明

贪心算法

这里先把这道题的核心算法简单说一下,后面有贴详细题解的链接。
规定第i个人最初有Ai个糖果,会给第i-1个人Xi个糖果(-Xi),接受第i+1个人给的Xi+1个糖果,此时第i个人手里有ave个糖果(xi有正负,即用正负,正代表与所假设的传递方向是正确的)Ai-Xi+Xi+1=ave
假设标号为i的小朋友开始有Ai颗糖果,Xi表示第i个小朋友给了第i-1个小朋友Xi颗糖果,如果Xi<0,说明第i-1个小朋友给了第i个小朋友Xi颗糖果,特殊地,X1表示第一个小朋友给第n个小朋友的糖果数量。 所以最后的答案就是ans=|X1| + |X2| + |X3| + ……+ |Xn|。 对于第一个小朋友,他给了第n个小朋友X1颗糖果,还剩A1-X1颗糖果;但因为第2个小朋友给了他X2颗糖果,所以最后还剩A1-X1+X2颗糖果。根据题意,最后的糖果数量等于ave,即得到了一个方程:A1-X1+X2=ave。
同理,对于第2个小朋友,有A2-X2+X3=ave。最终,我们可以得到n个方程,一共有n个变量,但是因为从前n-1个方程可以推导出最后一个方程,所以实际上只有n-1个方程是有用的。
尽管无法直接解出答案,但可以用X1表示出其他的Xi,那么本题就变成了单变量的极值问题。(用x1表示x2,x3,......xn)
对于第1个小朋友,A1-X1+X2=ave -> X2=ave-A1+X1 = X1-C1(假设C1=A1-ave,下面类似)

对于第2个小朋友,A2-X2+X3=ave -> X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2

对于第3个小朋友,A3-X3+X4=ave -> X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3

…… 对于第n个小朋友,An-Xn+X1=ave。

我们希望Xi的绝对值之和尽量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要尽量小。注意到|X1-Ci|的几何意义是数轴上的点X1到Ci的距离,所以问题变成了:给定数轴上的n(注意,是n个点,不要忘了0!!!!)个点,找出一个到他们的距离之和尽量小的点,而这个点就是这些数中的中位数,证明略。(|X1-0| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|)

代码如下

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long long int a[1000005],s[1000005];
int main()
{
	long long int n,i,store=0,ave,temp;
	long double flag,res=0;
	cin>>n;
	for(i=1;i<=n;i++){
		cin>>a[i];
		store+=a[i];
		s[i]=store;//A1加到Ai 
	}
	ave=store/n;//取平均数 
	s[0]=0;
	for(i=1;i<=n-1;i++) s[i]-=i*ave;//Ci 
	sort(s,s+n);
	if(n%2!=0) flag=s[n/2];
	else flag=1.0*(s[n/2]+s[n/2-1])/2;
	for(i=0;i<n;i++) res+=fabs(flag-1.0*s[i]);
	temp=res;
	cout<<temp;
	return 0;
}

注意点

·首先是要注意算法。这题的算法我是在是不会。。。我只知道应该是贪心类型的算法(我好垃圾5555)。在网上直接搜了题目,结果直接搜到lvhang写的博客???然后就顺藤摸瓜找到了在洛谷中的基本一样的题目。题目 题解

·接着就是数据类型的选择。求中位数时需要使用浮点型数据(如在偶数个数的数据中求中位数,需要相加再除以二,可能整除不了),使用整型数据会在丢失精度,造成错误。这点很致命。

`数组开的大小,题目给出的n范围是n<1e6,也就是1*10^6,特别注意,我的数组到后来才开够!!!!

·还有就是需要在n个数中寻找中位数,是n个数字!!!,|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|,即|X1-0| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|,不要把0漏了。

·输出格式应该选用整型数据输出(为什么用题目示例测试时使用double会输出4?)

·输出格式的最后一句话:答案保证可以用64位有符号整数存储 ,说明数据类型的选择应该要开比较大的。这一点我在耗了至少有一个小时以后才发现,找bug找了半天,吐了。

总之,算是AC了。。。。。

posted @ 2020-03-02 01:16  枭魈  阅读(332)  评论(0编辑  收藏  举报