两个吃奶一个添下面视频_人妻第一页香蕉网_欧美xxxx少妇_妺妺窝人体色www婷婷

一、什么是單調棧和單調隊列?

(1)單調棧

從名字上就聽的出來,單調棧中存放的數據應該是嚴格單調有序的,具有以下兩個性質。

1. 滿足從棧頂到棧底的元素具有嚴格的單調遞增或單調遞減性;

2. 滿足棧的后進先出特性,即越靠近棧底的元素越早進棧。


單調棧也分為單調遞增棧和單調遞減棧。

1. 單調遞增棧:單調遞增棧就是從棧底到棧頂數據是從小到大

2. 單調遞減棧:單調遞減棧就是從棧底到棧頂數據是從大到小


單調棧的維護

如何維護一個單調棧?出棧很簡單,與普通棧相同,關鍵操作是入棧


具體進棧過程

1. 對于單調遞增棧,若當前進棧元素為e,從棧頂開始遍歷元素,把小于e或者等于e的元素彈出棧,直接遇到一個大于e的元素或者棧為空為止,然后再把e壓入棧中。

2. 對于單調遞減棧,則每次彈出的是大于e或者等于e的元素。


于一個元素a,如果??談t直接入棧。否則比較a與棧頂元素。假設一個單調遞增的棧,若a > 棧頂元素,則直接把a入棧,棧仍滿足單調的性質。若a < 棧頂元素,則將棧頂元素出棧,直到滿足a < 棧頂元素,此時將a入棧。


(2)單調隊列

隊列中元素之間的關系具有嚴格單調有序性,而且,隊首和隊尾都可以進行出隊操作,只有隊尾可以進行入隊操作。因此,在單調隊列中求最值十分容易。

單調隊列與普通隊列有些不同,因為右端既可以插入又可以刪除,因此在代碼中通常用一份數組和rear與rear兩個指針來實現,而不是使用STL中的queue。如果一定要使用STL ,那么則可以使用雙端隊列(即兩端都可以插入和刪除),即deque 。


隊列的大小問題

在談及單調棧時,無需關心棧的大小。而對于隊列,隊列的大小就很重要了。如果隊列滿了,我們的解決方法是,將隊列頭的元素彈出,再添加新的元素到隊列尾。


單調隊列的維護

具體入隊過程

1. 對于單調遞增隊列,設當前準備入隊的元素為e,從隊尾開始把隊列中的元素逐個與e對比,把比e大或者與e相等的元素逐個刪除,直到遇到一個比e小的元素或者隊列為空為止,然后把當前元素e插入到隊尾。

2. 對于單調遞減隊列也是同樣道理,只不過從隊尾刪除的是比e小或者與e相等的元素。


(3)單調棧與單調隊列

單調隊列

1. 可以查詢區(qū)間最值(不能維護區(qū)間k大,因為隊列中很有可能沒有k個元素);

2. 優(yōu)化DP,單調隊列一般是用于優(yōu)化動態(tài)規(guī)劃方面問題的一種特殊數據結構,且多數情況是與定長連續(xù)子區(qū)間問題相關聯。

單調棧

1. 左邊區(qū)間第一個比它小的數,第一個比它大的數

2. 確定這個元素是否是區(qū)間最值

3. 右邊區(qū)間第一個大于它的值

4. 到右邊區(qū)間第一個大于它的值 的距離

5. 確定以該元素為最值的最長區(qū)間


相同點:

1. 單調隊列和單調棧的“頭部”都是最先添加的元素,“尾部”都是最后添加的元素。

2. 遞增和遞減的判斷依據相同:從棧底(隊尾)到棧頂(隊首),元素大小的變化情況。所以隊列和棧是相反的。

3. 兩者維護的時間復雜度都是O(n),每個元素都只操作一次。


不同點:

1. 單調隊列可以從隊列頭彈出元素,可以方便地根據入隊的時間順序(訪問的順序)刪除元素。

2. 單調隊列和單調棧維護的區(qū)間不同。當訪問到第i個元素時,單調棧維護的區(qū)間為[ 0 , i ),而單調隊列維護的區(qū)間為( lastpop , i ) 

3. 單調棧無法獲取[ 0 , i )的區(qū)間最大值/最小值。因為單調隊列可以訪問“頭部”和“尾部”,而單調棧只能訪問棧頂(也就是“尾部”)。


二、單調隊列/單調棧優(yōu)化

例題一:單調隊列優(yōu)化

題目描述: 有 n 頭奶牛在一排,每頭奶牛的價值為 vi ,你可以選擇若干頭奶牛,但不能選擇超過 k 頭連續(xù)的奶牛。求價值之和最大為多少。n<=1e5

狀態(tài)設置: f [ i ] :選擇了若干頭牛,最后一頭牛是第 i 頭牛的最大價值。

問題分析: 顯然,[ i ? k , i ? 1 ] 中有一頭牛不能選,我們可以枚舉這頭牛的位置。

轉移方程:f [ i ] = max ( f [ j ? 1 ] + sum [ i ] ? sum [ j ] ) , j ∈ [ i ? k , i ? 1 ] 

時間復雜度:時間復雜度

單調隊列優(yōu)化

f [ i ] = max ( f [ j ? 1 ] ? sum [ j ] ) + sum [ i ], j ∈ [ i ? k , i ? 1 ] 

g [ i ] = f [ i ? 1 ] + sum [ i ] ,維護 g [ i ] 的區(qū)間最大值即可。

補充: 其實可以直接用線段樹維護區(qū)間最值,時間復雜度 O(nlogn)

代碼如下:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
long long f[N];//表示選擇了若干頭牛,最后一頭牛是第 i 頭牛的情況下,的最大價值 
long long g[N];//g[i]=f[i-1]-sum[i] 
long long sum[N],a[N],que[N],head,rear;
int main(){
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum[i]=sum[i-1]+a[i]; 
	}
	long long ans=sum[1];
	f[1]=sum[1];
	g[0]=0;
	g[1]=-sum[1];
	que[rear++]=0;
	que[rear++]=1;
	for(int i=2;i<=n;i++){
		while(head<rear&&i-que[head]>k)head++;//維護范圍限制 
	    f[i]=g[que[head]]+sum[i];//狀態(tài)轉移 
		g[i]=f[i-1]-sum[i];//計算新的要維護的值 
		while(head<rear&&g[i]>g[que[rear-1]])rear--;//加入新的要維護的值 
		que[rear++]=i;
		
		ans=max(ans,f[i]); 
	} 
	cout<<ans;
}

這塊需要大家多多練習,才能更好的靈活運用。



點贊(0)

C語言網提供由在職研發(fā)工程師或ACM藍橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習題和答疑,點擊了解:

一點編程也不會寫的:零基礎C語言學練課程

解決困擾你多年的C語言疑難雜癥特性的C語言進階課程

從零到寫出一個爬蟲的Python編程課程

只會語法寫不出代碼?手把手帶你寫100個編程真題的編程百練課程

信息學奧賽或C++選手的 必學C++課程

藍橋杯ACM、信息學奧賽的必學課程:算法競賽課入門課程

手把手講解近五年真題的藍橋杯輔導課程

Dotcpp在線編譯      (登錄可減少運行等待時間)