#10010 「一本通 1.1 练习 6」糖果传递 (数学+贪心)
題目描述
原題來自:HAOI 2008
有 n個小朋友坐成一圈,每人有 ai 顆糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一顆糖果的代價為 1 。求使所有人獲得均等糖果的最小代價。
輸入格式
第一行有一個整數??,n表示小朋友個數;
在接下來 n行中,每行一個整數?。
輸出格式
輸出使所有人獲得均等糖果的最小代價。
樣例
樣例輸入
4 1 2 5 4樣例輸出
4數據范圍與提示
對于 30% 的數據,n<1000;
對于100%? 的數據,n<10^9,保證答案可以用64? 位有符號整數存儲。
題目鏈接:https://loj.ac/problem/10010
對于這道,emmmm據說是小學奧賽題,我看博客半小時才弄通,最后發現是自家會長的博客,O(∩_∩)O哈哈~
跪拜大佬:https://blog.csdn.net/qq_41890797/article/details/90244567
我對這道數學題的思路:
1.設未知數; 2.求公式;3.求中位數的負數;^_^ha大廢話,顯然覺的這道題有很多值得深入挖掘的性質,比如每個人最終的狀態求個平均值就好了 。那么先不考慮算法(好像也不涉及算法),而是研究一波題面。?
1.顯然,代價的計算是一個麻煩的事情。我認為代價的計算應該是與路徑有關,而不是與人有關。也就是說,我們關心的是兩個人之間的路徑上糖果移動的情況,可以設Xi:Ai—>Ai+1為糖果的路徑轉移。?
2.我又發現,一條路徑上糖果的移動方向只有一個,可以用正負來表示。接著我們還發現,只要知道了一條路徑上糖果的移動情況,那么其他路徑也是可以推出來的。?
這時,公式已經出來了,也就是求出平均數然后列出每一條路徑的糖果運送情況得到的,得到固定值Si的中位數,讓Xn為中位數的相反數即可;
每人每次傳遞一個糖果代價為1
?
推公式過程
本題用到遞推和貪心的算法思想,偏重對數學思維的檢測。
(1).需要注意的題中條件:
? ? ? ? ? <1>.首先要明確:n個人圍成環坐;?
? ? ? ? ? <2>.只能左右傳遞;
? ? ? ? ? ?<3>.使得每個人得到均等的餃子ave;
?(2).找出遞推式?
? ? ? ? ? <1>關注的每兩個人之間的路徑上餃子移動的情況。?
? ? ? ? ? <2> 設第i個人會給第i+1個人xi個糖果(帶符號)即下圖:那么 ?ai-xi+xi-1=ave;
?? ?
? ? ? ? ? ? ? ? ?? ?1 ? ? ? ?2 ? ? ? ?3 ? ? ? ?4
? ? ? ? ? ? ? ? 初始值: ? 1 ? ? ? ?2 ? ? ? ? 5 ? ? ? 4
? ? ? ? ? ? ? ? 最終值: ? 3 ? ? ? ?3 ? ? ? ? 3 ? ? ? 3
? ? ? ? ? ? ? ? 移動情況:-2 ? ? ?-1 ? ? ? ?2 ? ? ? ?1
? ? ? ? ? <3>將所有的式子列出來然后每一個做一個前綴和:那么xn?xi=∑ai?ave。
? ? ? ? ? <5> 變形:xi=xn?(∑ai?ave)。((∑ai?ave)為一個常量,簡寫為k)
? ? ? ? ?<4>找到遞推式,要求∑|xi|最小實際上就是要求∑|xn?k|最小 。利用絕對值的幾何意義,那么xn取這些常量k里的中位數時,憤怒值有最小值.
上代碼:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; typedef long long ll; const int M=1e6+10; int a[M],s[M]; int main() {int n;ll sum=0;scanf("%d",&n);for(int i=1; i<=n; i++){scanf("%d",&a[i]);sum+=a[i];}ll ave=sum/n,ans=0;for(int i=1; i<=n; i++)s[i]=(a[i]-ave)+s[i-1];///減平均值后的前綴和sort(s+1,s+1+n);///為求中位數for(int i=1; i<=n; i++)ans+=abs(s[i]+(-s[(n+1)>>1]));///找(s[(n+1)>>1]為中位數)的負數printf("%lld\n",ans);return 0; }?
總結
以上是生活随笔為你收集整理的#10010 「一本通 1.1 练习 6」糖果传递 (数学+贪心)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消息称特斯拉本周将针对全系车型再次涨价
- 下一篇: Steam Deck 掌机获推 Stea