1. 程式人生 > >●BZOJ 3831 [Poi2014]Little Bird

●BZOJ 3831 [Poi2014]Little Bird

space body read off pos blank getch class esp

題鏈:

http://www.lydsy.com/JudgeOnline/problem.php?id=3831
題解: 單調隊列優化DP 定義 F[i] 為到達第i課樹的疲勞值 顯然最暴力的轉移就是枚舉i位置前面的k個位置,找到最優的位置跳過來。 每一個詢問的復雜度 O(KN),最壞達到O(N²)。 考慮優化: 設H為高度的話,對於兩個轉移來源位置x,y(x<y),如何如何判斷那個更優呢? 有如下4種情況: 1).H[y]≥H[x]且F[y]≤F[x],則任何時候選擇y都不會比選擇x差,所以從單調隊列裏去掉x。 2).H[y]≥H[x]且F[y]>F[x],在 x 由於距離原因而出隊之前,選擇x都不會比選擇y差,所以把y放在隊尾。
3).H[y]<H[x]且F[y]<F[x],則任何時候選擇y都不會比選擇x差,所以從單調隊列裏去掉x。 4).H[y]<H[x]且F[y]≥F[x],在 x 由於距離原因而出隊之前,選擇x都不會比選擇y差,所以把y放在隊尾。 然後用單調隊列維護就可以啦,每一個詢問的復雜度O(N)。 代碼:
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 1000500
using namespace std;
int H[MAXN],F[MAXN];
int N,Q;
void read(int &x){
	static int f; static char ch;
	x=0; f=1; ch=getchar();
	while(ch<‘0‘||‘9‘<ch){if(ch==‘-‘)f=-1;ch=getchar();}
	while(‘0‘<=ch&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	x=x*f;
}
bool off(int x,int y){
	if(H[y]>=H[x]){
		if(F[y]<=F[x]) return 1;
		else return 0;
	}
	else{
		if(F[y]<F[x]) return 1;
		else return 0;
	}
}
int main(){
	static int pos[MAXN],l,r;
	read(N);
	for(int i=1;i<=N;i++) read(H[i]);
	read(Q);
	for(int q=1,k;q<=Q;q++){
		read(k); l=1; r=0;
		F[1]=0; pos[++r]=1;
		for(int i=2;i<=N;i++){
			while(l<=r&&i-pos[l]>k) l++;
			F[i]=F[pos[l]]+(H[pos[l]]<=H[i]);
			while(l<=r&&off(pos[r],i)) r--;
			pos[++r]=i;
		}
		printf("%d\n",F[N]);
	}
	return 0;
}

  

●BZOJ 3831 [Poi2014]Little Bird