洛谷題面
和題解差不多,加了點證明。
有 \(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,等...