python直譯器安裝與使用
阿新 • • 發佈:2022-03-02
首先,單調佇列的作用是維護區間最大值
比如說現在我們看上面這個圖吧,現在把這些數,每三個化成一個視窗。在每個視窗後面藍色部分,從左到右寫出視窗中有可能成為區間最大值的元素。然後你會發現,所有的藍色部分的第一個數字好像就是相應的區間最大值,而且你會發現,每一個藍色部分好像都是遞減的。其實只要一個數後面有一個數比它大的話,那麼這個數就不可能會是區間最大值。那麼我要怎麼維護這樣一個數據結構呢?這個地方就需要用到單調隊列了。
現在用自然語言描述一遍吧。首先把6,3,2入佇列,然後5入隊,由於需要維護單調遞減,所以把3和2踢出去(這個描述的確有一點詭異),這個所謂的踢出去是往後移麼?然後發現已經4個了超出視窗了。所以把6給丟出去。然後把4和1入隊。依次類推上面的元素上面都有一個對應的區間最大值。
後面來一題例題,後面其實還是可以再看看別人的部落格的。
所以為什麼要進行演算法的訓練呢,像很多之前的學習中,其實我對演算法都不夠熟練,我後面可能還會花很多時間去熟悉各種演算法,其實這題一開始就有點繞,但是自己還是很認真去看了。
首先如果有經過演算法訓練的話(很顯然我這個菜雞是沒有的),看到連續子列和,就要想到轉化為字首和問題。因為一個子列的字首和就是這個資料的最後一個字首和減去第一個字首和。而且這個地方還要有一個s0來記錄第0號位置(這個也是有意義的,比如說我要訪問前j個元素的話,就是從sj一直到s0)。
後面來看程式碼把,這個程式碼我看了很久(腦子笨),但是總算是看懂了,希望後面自己可以多打幾遍吧!
#include <iostream> using namespace std; #define MAX_N 300000 int q[MAX_N + 5], head, tail; int arr[MAX_N + 5]; int main() { int n, m,ans; cin >> n >> m; for (int i = 1; i <= n; i++) cin >> arr[i], arr[i] += arr[i - 1]; head = tail = 0; //這個地方有一個技巧,就是在佇列裡面儲存的是arr下標q[tail++] = 0;//先把第一個位置上放上0號位的下標 ans = arr[1]; for (int i = 1; i <= n; i++) { ans = max(ans, arr[i] - arr[q[head]]); //ans要大的話就要使這個佇列是一個遞增佇列 //這樣隊頭元素就是最小的元素了,相減得到的元素是最大的 while (tail - head && arr[q[tail - 1]] >= arr[i]) tail--; //這裡其實就是把tail移動到相應的位置上去 q[tail++] = i; //後面判斷會不會超出範圍,如果超出的話就把head++就好了,也就是head存的下標裡i的距離超過了m if (q[head] == i - m) head++;
} cout << ans << endl; return 0; }
這個地方有一個技巧就是佇列中存的是arr陣列的下標,這點就很妙了。這樣方便對資料的處理。還有就是字首和這個東西其實就是一個元素加上上一個元素,也就是前n項和了。