HAOI2008 糖果傳遞

2022-10-08 19:21:11 字數 2840 閱讀 9439

洛谷題面

和題解差不多,加了點證明。

有 \(n\) 個小朋友坐成一圈,每人有 \(a_i\) 個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞乙個糖果代價為 \(1\)。

設 \(**e\) 表示所有小朋友糖果數量的平均數,因為所有小朋友糖果總數不會變,所以最後每個人的糖果數都會變成平均數。設 \(num_i\) 表示第 \(i\) 個小朋友往左傳的糖果數。

若 \(num_i\) 為負數,表示向右傳。

可知:\[a_1+num_2-num_1=**e

\]\[a_2+num_3-num_2=**e

\]\[\cdots

\]\[a_n+num_1-num_n=**e

\]一般地:

\[a_i+num_-num_i=**e(1\le i\lt n)

\]\[a_i+num_-num_=**e(i=n)

\]我們只保留 \(num\):

\[num_=**e+num_1-a_1

\]\[num_=**e+num_2-a_2=**e+(**e+num_1-a_1)-a_2=2

\cdot **e+num_1-a_1-a_2\]

\[\cdots

\]\[num_1=**e+num_n-a_n=\dots=n\cdot **e+num_1-a_1-a_2-\dots-a_n

\]我們引入 \(c\) 陣列,定義:

\[c_i=(\sum\limits_^na_j)-i\cdot **e

\]故有:

\[num_2=num_1-c_

\]\[num_3=num_1-c_2

\]\[\cdots

\]\[num_n=num_1-c_n

\]一般地:

\[num_i=num_1-c_i

\]題目要求我們最小化 \(|num_1|+|num_2|+\cdots+|num_n|\),亦即最小化 \(|num_1-c_1|+|num_1-c_2|+\cdots+|num_1-c_n|\)。

將 \(c_i\) 看作數軸上的點,問題轉換為找出乙個點 \(num_1\) 使得所有點到 \(num_1\) 距離和最小。

結論:\(num_1\) 為 \(c_i\) 的中位數時距離和最小。

證明:數學歸納法。

秩:區間內任意取值均使得全域性最優時,預設取左端點。

當有兩個數時,顯然 \(num_1\) 取在兩數之間的位置比較好,為了使模型一般化,我們的 \(num_1\) 取為 \(c_1\)。此時 \(num_1\) 為 \(c\) 的中位數。

當有三個數時,假設排序後為 \(c_1,c_2,c_3\),那麼 \(num_1\) 一定在 \(c_1,c_3\) 之間,取**呢?發現放在之間的話,\(|c_1-num_1|+|c_3-num_1|\) 不變,所以我們只需要最小化 \(|c_2-num_1|\)。易得 \(num_1=c_2\) 時最小,此時 \(num_1\) 為 \(c\) 的中位數。

當有四個數時,抽象成兩個數時的模型,根據我們的「秩」,\(num_1\) 取 \(c_2\)。

以此類推。

\(\rm q.e.d.\)

於是我們可以求出 \(num_1,num_2,num_3,\cdots,num_n\),\(|num_1|+|num_2|+\cdots+|num_n|\) 也就不難得到了。

//2022/3/10

#define _crt_secure_no_warnings

#include #include #include //need "int_max","int_min"

#include //need "memset"

#include #include #define int long long

#define enter() putchar(10)

#define debug(c,que) cerr << #c << " = " << c << que

#define cek(c) puts(c)

#define blow(arr,st,ed,w) for(register int i = (st);i <= (ed); ++ i) cout << arr[i] << w;

#define speed_up() cin.tie(0),cout.tie(0)

#define mst(a,k) memset(a,k,sizeof(a))

#define abs(x) ((x) > 0 ? (x) : -(x))

const int mod = 1e9 + 7;

inline int mod(int x)

namespace newstd

inline int read()

while (isdigit(ch))

return f ? -ret : ret;

} inline void write(int x)

if(x > 9) write(x / 10);

putchar(x % 10 + '0'); }}

using namespace newstd;

using namespace std;

const int ma = 1e6 + 5;

int a[ma],sum[ma],c[ma];

int n,**e;

#undef int

int main(void)

sort(c + 1,c + n + 1);

int ans = 0,standard = c[n / 2];

for (register int i = 1;i <= n; ++ i)

printf("%lld\n",ans);

return 0;

}

BZOJ 1045 HAOI2008 糖果傳遞

有n個小朋友坐成一圈,每人有ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞乙個糖果代價為1。第一行乙個正整數n 987654321,表示小朋友的個數 接下來n行,每行乙個整數ai,表示第i個小朋友得到的 糖果的顆數 求使所有人獲得均等糖果的最小代價。4 1254 4 結論題 設每個人剛開始有a...

BZOJ1045 HAOI2008 糖果傳遞

貪心w 設每個人原來的糖果數為ai,最後的糖果數為k 即平均數 第1個人給了第n個人x1顆糖 第i個人給了第 i 1 個人xi顆糖 i 1 那麼ans x 1 x1 x 2 x2 x n xn k a1 x1 x2 a2 x2 x3 an 1 xn 1 xn an xn x1 即x2 x1 k a1...

BZOJ1045 HAOI2008糖果傳遞(貪心)

顯然最後每個小朋友所擁有的糖果數就是糖果數總和的平均數。設該平均數為t。環的問題一般斷成鏈,但這個題似乎沒有什麼很好的辦法在列舉斷點的時候快速算出答案 我甚至不知道會不會有斷點 於是我們假裝把他斷開了。假裝現在我們已經知道了1號小朋友要給n號小朋友x顆糖果 可以為負 那麼,2給1,3給2,4給3,等...