《算法竞赛进阶指南》打卡-基本算法-AcWing 102. 最佳牛围栏:浮点数二分、前缀和、双指针
文章目錄
- 題目
- 題解
題目
農夫約翰的農場由 N 塊田地組成,每塊地里都有一定數量的牛,其數量不會少于 1 頭,也不會超過 2000 頭。
約翰希望用圍欄將一部分連續的田地圍起來,并使得圍起來的區域內每塊地包含的牛的數量的平均值達到最大。
圍起區域內至少需要包含 F 塊地,其中 F 會在輸入中給出。
在給定條件下,計算圍起區域內每塊地包含的牛的數量的平均值可能的最大值是多少。
輸入格式
第一行輸入整數 N 和 F,數據間用空格隔開。
接下來 N 行,每行輸入一個整數,第 i+1 行輸入的整數代表第 i 片區域內包含的牛的數目。
輸出格式
輸出一個整數,表示平均值的最大值乘以 1000 再 向下取整 之后得到的結果。
數據范圍
1≤N≤100000
1≤F≤N
輸入樣例:
輸出樣例:
6500題解
來源:最佳牛圍欄
題目分析
選取長度最短為f的子序列,其平均值最大。這里的難度在于長度可以大于f,而不是固定f。
我們的思路是,平均值最大問題(最優化問題)轉化為一個判定問題:猜想(二分)出來一個平均值mid,判斷是否存在一個長度大于等于f的連續子序列滿足。
有關平均值的常用技巧:一個序列的平均值大于mid ?\Longleftrightarrow?把序列中每個元素都減去mid,然后求和,只要和大于0
使用雙指針:i 和 j,其間隔為f。需要記錄i指針前面部分的最小值,每次判斷sum[j]大于等于i前面區間的最小值:sum[j] ≥ min[sum(0 ~ i)],如果滿足,則二分往后半區間移動。
注意,這里就滿足了區間長度大于等于m:因為i 和 j已經間隔m,然后如果取i前面的值,則區間長度大于m。
在代碼中:minv是最小的前綴和,sum[j]也是前綴和,只要sum[j]減去minv大于零,表示從前綴和是minv的位置到j這個區間中的所有值的和大于0,也就是平均值大于mid。
時間復雜度: O(nlogr)O(nlogr)O(nlogr),其中r為二分的長度,這里是≤ 2000,n為序列的長度。
ac代碼
#include <bits/stdc++.h>using namespace std; const int N = 1e5 + 10; int cows[N]; int n, m; double sum[N];bool check(double avg) {// 每個數變成它減去平均數,再求前綴和for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + cows[i] - avg;double minv = 0;// 雙指針for (int i = 0, j = m; j <= n; j ++, i ++) {minv = min(minv, sum[i]); // [0, i]的最小值if (sum[j] >= minv) return true; // sum[j] >= minv:存在長度≥m,且平均值≥ avg}return false; }int main() {cin >> n >> m;for (int i = 1; i <= n; i ++) cin >> cows[i];double l = 0, r = 2000; // 可取的平均值一定在[0, 2000]之間// 二分平均值while (r - l > 1e-5) {double mid = (l + r) / 2;if (check(mid)) l = mid; // 如果mid滿足啦,就判斷更大的平均值,即l = midelse r = mid;}cout << int(r * 1000) << endl;} 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的《算法竞赛进阶指南》打卡-基本算法-AcWing 102. 最佳牛围栏:浮点数二分、前缀和、双指针的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tensorflow遇到的问题Inval
- 下一篇: 《Deep Learning With