CTU Open Contest 2019 F题 Beer Marathon(思维题)

题目描述

在这里插入图片描述
在这里插入图片描述

题目大意

       有n个点排成一排,给出了它们的位置坐标,现在需要将它们按照相同的间隔k重新排列,问所有点需要移动的距离之和的最小值是多少?

分析过程

通过观察,可以发现两个小结论:

结论1   重新调整之后的排列至少存在一个位置与调整之前的相应位置重合。

可以用反证法证明:
       设原序列(升序排列之后的)集合为A,我们假设已经获得了一个满足最优方案的序列集合B,若对于 x A , y B \forall x\in A,\forall y\in B 均有 x y x\not=y ,此时,有3种情况:若A中的位置点 ai 大部分位于其对应位置bi的左侧时,此时我们将B向左移动一个单位必然可以使得结果更优(左边对减少距离的贡献更大);反之,向右移动更优,以上这两种情况均与假设中的“最优方案”矛盾;若A中的位置点均匀的散布在最优方案点的两侧,那么此时我们必然可以通过移动B而使得A与B之间存在相交点。综上所述,结论1得证。

结论2   由结论1的证明过程可以看出,在原序列中必然存在一个基准位置ai,当将序列a1,a1+k,a1+2k,…,a1+(n-1)k 中的对应位置(即 a1+(i-1)k)和 ai 对齐时,此时序列A中的点相对于间隔为k的序列的相应位置点来说,左右散布是均匀的,此时我们就得到了最优方案,即题中所求。

       有了以上2个分析得到的结论做支撑之后,我们的问题就转化为了如何在原序列A中寻找基准位置。很显然一个一个枚举的时间复杂度是O(n2),必然要TLE。通过观察,我们发现,当把原序列A中的第一个位置作为基准位置时(选别的位置也行,但选第一个最方便),我们从左到右遍历一遍,将原序列A与标准序列a1,a1+k,a1+2k,…,a1+(n-1)k 分别作差。此时,差值处于中间的那个位置便是基准位置。(因为此时该位置能够均匀的将A序列各位置散布在a1,a1+k,a1+2k,…,a1+(n-1)k 序列位置点的左右两侧)

       综上,我们得到的做法为:先将原序列x进行升序排列,与标准序列a1,a1+k,a1+2k,…,a1+(n-1)k 分别做差,最后找中间值确定基准位置,最后计算结果。时间复杂度为 O ( n log n ) O(n\log n)

附AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 1000;
ll x[maxn];
int main(){
	ll n,k,i,ans = 0;
	ios::sync_with_stdio(false);
	cin>>n>>k;
	for(i=1;i<=n;++i) cin>>x[i];
	sort(x+1,x+n+1);
	//判断在左对齐的情况下,每个点和标准点的相对位置(求差),符号为正说明在标准点右侧,否则在左侧 
	for(i=2;i<=n;++i){ 
		x[i] -= (i - 1) * k;
	}
	sort(x+1,x+n+1);
	ll mid = x[(1+n)/2];
	for(i=1;i<=n;++i) ans += abs(x[i] - mid);
	cout<<ans;
	return 0;
} 

Another Solution

       如上文所述,实际上标准排列a1,a1+k,a1+2k,…,a1+(n-1)k在原序列A中左右移动时,会使得总距离要么向左边方向增大,要么向右边方向增大,在其中间存在一个点取得最优方案。可以发现,这个总距离随坐标变化的图像是一个单峰曲线。因此,我们也可以使用三分法求解该问题。

发布了1 篇原创文章 · 获赞 0 · 访问量 69

猜你喜欢

转载自blog.csdn.net/qq_42968686/article/details/104470772