1. 程式人生 > >佇列_單調佇列_CH1201_最大子序和

佇列_單調佇列_CH1201_最大子序和

思路分析:

    這是一道典型的單調佇列應用問題, 先給出AC程式碼, 然後給出程式正確性證明和時間複雜度分析.

//CH1201_最大子序和
#include <cstdio>
#include <algorithm>
#include <deque>
using namespace std;
const int MAXN = 3e5 + 5; const long long NIL = 1e18;
long long psum[MAXN];//字首和陣列 
int main(){
	int n, m; scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%lld", &psum[i]), psum[i] += psum[i - 1]; 
	deque<int> de(1, 1); long long ans = psum[1];
	for(int i = 2; i <= n; ++i){		
		if(de[0] < i - m) de.pop_front();
		ans = max(ans, psum[i] - psum[de[0]]);
		while(!de.empty() && psum[de.back()] >= psum[i]) de.pop_back();
		de.push_back(i);		
	}
	printf("%lld\n", ans);
} 

(1)程式正確性證明:

     設輸入序列為a_{1}...a_{n},考慮證明 每次第12至17行迴圈頭檢測之前均有ans = max{完全位於a_{1}...a_{i - 1}的非空連續子段的和}, 且滿足i > k >= i - m, 最小的psum[k]對應的最大k值在佇列de中, 顯然當i = 2時該結論成立. 假設當i <= b 時該結論成立, 對於i = b + 1, 分兩種情況考慮, 如果滿足b + 1 > k >= b + 1 - m, 最小的psum[k]對應的最大k值與滿足b > k >= b - m, 最小的psum[k]對應的最大k值相同, 那麼上述結論顯然成立, 如果滿足b + 1 > k >= b + 1 - m, 最小的psum[k]對應的最大k值比滿足b > k >= b - m ,最小的psum[k]對應的最大k值大, 設該值為q, 考慮對於i為q...b時程式的執行情況, 顯然min{a_{q}...a_{b}

} = a_{q}a_{q + 1}...a_{b}均大於a_{q}, 因此對於i = b + 1時的迴圈頭檢測上述結論依然成立, 特別的, 如果第b + 1次迴圈頭檢測之前佇列de中有元素不在區間[b + 1 - m, b]中, 那麼只能是de的隊頭元素, 這是因為當i = b時, 該隊頭元素在區間[b - m, b]中. 根據上述結論易知程式正確.

(2)時間複雜度分析:

    對於第12至17行的迴圈, 每個元素至多入佇列de一次和出佇列一次, 因此該程式的時間複雜度為O(n)