Codeforces Round #686 (Div. 3) F. Array Partition

題意:找到三個正整數x、y、z
知足下面兩個條件在這裏插入圖片描述
思路:首先咱們很容易處理獲得先後綴的最大值,前綴最大值直接遍歷過去就好,後綴最大值開個數組suf維護後綴最大值便可。對於中間那部分,由於不存在修改操做,是個靜態的區間問題,預處理打個st表便可。
而後咱們難點在於如何找到x+y的位置,知足等式


c++

首先,咱們要知道這麼兩個常識。
區間最小值會隨着區間長度增大而保持不變或者減少
區間最大值會隨着區間長度增大而保持不變或者增大
那麼這裏就有了單調性
因此咱們枚舉每一個位置做爲x,而後經過二分獲得x+y的位置。
一、若是前綴最大值ma>min(x+1,x+y) 說明區間最小值過小了,要增大他,那麼就要讓區間長度變小,由於左端點是不變的,因此讓r=m,縮小右端點。
二、若是前綴最大值ma<min(x+1,x+y) 說明區間最小值過大,要減小他,那麼就要讓區間長度增大,左端點不變,全部就讓l=m,擴大右端點。
三、若是知足ma=min(x+1,x+y),咱們還須要比較ma和後綴最大值,即max(x+y+1,n),若是前綴最大值更大,說明後綴偏小,那麼要擴大區間長度,由於右端點n不變,因此要讓左端點x+y+1縮小,即讓r=m,反之讓l=m.






數組

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+50;
int lg[N],st[N][20];
int suf[N],a[N];
int getMin(int l,int r){ 
	int k=lg[r-l+1];
	return min(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){ 
	for(int i=2;i<N;i++){ 
		lg[i]=lg[i-1];
		if(i%2==0) lg[i]=lg[i/2]+1;
	}

	int T;cin>>T;
	while(T--){ 
		int n;cin>>n;
		for(int i=1;i<=n;i++){ 
			cin>>a[i];
			st[i][0]=a[i];
		}
		for(int j=1;j<=18;j++){ 
			for(int i=1;i<=n;i++){ 
				st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
			}
		}
		suf[n]=a[n];
		for(int i=n-1;i;i--) suf[i]=max(suf[i+1],a[i]);
		int k=0;
		int ma=0;
		for(int i=1;i<n;i++){ 
			ma=max(ma,a[i]);
			int l=i,r=n;
			while(l+1<r){ 
				int m=l+r>>1;
				int mi=getMin(i+1,m);
				if(ma>mi) r=m;
				else if(ma<mi) l=m;
				else { 
					if(ma>suf[m+1]) r=m;
					else if(ma<suf[m+1]) l=m;
					else { 
						k=m;
						break;
					}
				}
			}
			if(k){ 
				cout<<"YES\n";
				cout<<i<<" "<<k-i<<" "<<n-k<<endl;
				break;
			}
		}
		if(!k) cout<<"NO\n";
	}

	return 0;
}
相關文章
相關標籤/搜索