CTU Open Contest 2019 F題 Beer Marathon(思維題)

題目描述

在這裏插入圖片描述
在這裏插入圖片描述

題目大意

       有n個點排成一排,給出了它們的位置座標,現在需要將它們按照相同的間隔k重新排列,問所有點需要移動的距離之和的最小值是多少?

分析過程

通過觀察,可以發現兩個小結論:

結論1   重新調整之後的排列至少存在一個位置與調整之前的相應位置重合。

可以用反證法證明:
       設原序列(升序排列之後的)集合爲A,我們假設已經獲得了一個滿足最優方案的序列集合B,若對於xA,yB\forall x\in A,\forall y\in B均有xyx\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(nlogn)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中左右移動時,會使得總距離要麼向左邊方向增大,要麼向右邊方向增大,在其中間存在一個點取得最優方案。可以發現,這個總距離隨座標變化的圖像是一個單峯曲線。因此,我們也可以使用三分法求解該問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章