1. 程式人生 > >2017.04.02【NOIP 普及組】模擬賽C組 T2:士兵

2017.04.02【NOIP 普及組】模擬賽C組 T2:士兵

士兵
題目描述

在Gridland國家,有N個處於不同位置的士兵。該國上的地方都用兩個座標(X,Y)來表示。士兵能進行一次移動,每個士兵都可向上、向下、向左、或向右移動一個單位長,這樣他就能把自己的X或Y改變1或-1。

士兵們想進入一個水平線,彼此靠近,這樣他們的最後位置就是(X,Y)、(X+1,Y),…,(X+N,Y))。水平線上的士兵的最後順序以及整數X和Y,都是任意的。

現在目標是求如此配置士兵的最少移動數。

兩個或兩個以上的士兵在同一時間不處於同一位置。

輸入

輸入檔案soldiers.in的第一行含有一個整數N,1 <= N <=10000,N為士兵的數量。輸入檔案以後的N行應含有士兵的初始位置,對於每一個i, 1<= i <= N,輸入檔案的第I+1行含有兩個用空格分開的整數x[i],y[i],他們表示第I個士兵的座標,-10000<=x[i],y[i] <=10000.

輸出

輸出檔案soldiers.out僅有一行,它的值為使士兵移動到水平線彼此相鄰的最小移動次數。

樣例輸入

5
1 2
2 2
1 3
3 -2
3 3

樣例輸出

8

題解:
此題就是一個噁心的數學規律題。
題意說:士兵們想進入一個水平線,彼此靠近,這樣他們的最後位置就是(X,Y)、(X+1,Y),…,(X+N,Y))。那麼我們就會發現,士兵們合在一條水平線的位置,就是水平線的中間那條線。如圖:
這裡寫圖片描述
紅色表示士兵。
中間的集合線是:
這裡寫圖片描述
藍色標記的線最優。

於是乎,我們就把所有士兵給直接集合到此直線(不管重合),得到:這裡寫圖片描述
圖中兩個紅圈表示有兩個士兵。
他們集合到一條直線所需次數:6.
現在,用一個x來表示每個紅圈的x座標,再排序。如圖例得:
1 1 2 3 3
再因為士兵要緊密相連,所以最終佇列應為:
這裡寫圖片描述


答案為6+2=8.
如何處理這一段???

我們就來看:x
1 1 2 3 3
排好隊最終的序號為:
1 2 3 4 5
再由想x[i]-i+1得:
1 0 0 0 -1
快排。
-1 0 0 0 1
從中間拓展,
於是搞搞就OK了。
標程:

type
        new=array[1..10000] of longint;
var
        a:array[1..10000] of longint;
        b,z:array[-10000..10000] of longint;
        x,y,x1,y1:array[1..10000] of longint;
        i,j,k,l,n,m,sum,mid:longint;
procedure
qs(l,r:longint;var a:new);
var i,j,m,t:longint; begin i:=l; j:=r; m:=a[(l+r)div 2]; repeat while a[i]<m do inc(i); while a[j]>m do dec(j); if i<=j then begin t:=a[i]; a[i]:=a[j]; a[j]:=t; inc(i); dec(j); end; until i>j; if l<j then qs(l,j,a); if i<r then qs(i,r,a); end; begin assign(input,'soldiers.in');reset(input); assign(output,'soldiers.out');rewrite(output); readln(n); for i:=1 to n do begin readln(x[i],y[i]); end; if n mod 2=1 then mid:=(n+1) div 2 else mid:=n div 2; qs(1,n,y); for i:=1 to n do begin sum:=sum+abs(y[i]-y[mid]); end; qs(1,n,x); for i:=1 to n do begin x[i]:=x[i]-i+1; end; qs(1,n,x); for i:=1 to n do begin sum:=sum+abs(x[i]-x[mid]); end; writeln(sum); close(input);close(output); end.