F. Array Partition (思维+单调栈)

传送门
题目大意:给一个数组,问能否把数组分为三段区间满足:
max(1,x)=min(x+1,x+y)=max(x+y+1,n).
某场Div3的最后一题.思维和编程难度都不算小.
考虑枚举一下这个数是多少,那么这个数起码在数组里要出现三次以上.只有这种数才有机会成为答案.
max和min有一个很明显的性质:当值域集合大小增大时,max会更大,min会更小.
那么对于每一个数来说,两个max区间只要取最左边和最右边的两个数即可,中间的数可以暴力枚举.只要这中间的数产生的区间和其他两个区间有交集即可成为答案.这样复杂度是O(n)的.
具体来说就是找到出现次数超过3次的数.然后找到最左边第一个数右边第一个比它大的位置,最右边一个数左边第一个比它大的位置.和枚举中间的数左右两边第一个小于它的位置,然后看这样子找到的区间有无交集(可以在纸上模拟一下这个过程).
而这个找左右第一个比它大小的方法可以用单调栈直接维护.
而计算每个数出现的次数用离散化和map都是O(nlogn)的.所以整体复杂度还是O(nlogn).
代码:

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>

using namespace std;
const int N = 2e5+10;

inline int read(){
    
    
	int x = 0,f=1;char ch = getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){
    
    x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int a[N],tn;
vi tmp[N];
vi all;
int getpos(int x){
    
    
	return lower_bound(ALL(all),x) - all.begin();
}
int lmax[N],rmax[N],lmin[N],rmin[N];
int main(){
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while(t--){
    
    
		int n;
		cin >> n;
		all.clear();all.pb(-1);
		fir(i,1,n) tmp[i].clear(),cin >> a[i],all.pb(a[i]);
		sort(ALL(all));
		all.erase(unique(ALL(all)),all.end());
		fir(i,1,n) a[i] = getpos(a[i]),lmax[i]=rmax[i]=lmin[i]=rmin[i]=0;
		fir(i,1,n) tmp[a[i]].pb(i);
		tn = all.size()-1;
		vi vec;
		fir(i,1,n){
    
    
			while(vec.size() && a[i] > a[vec.back()]) rmax[vec.back()] = i,vec.pop_back();
			vec.pb(i);
		}
		vec.clear();
		afir(i,n,1){
    
    
			while(vec.size() && a[i] > a[vec.back()]) lmax[vec.back()] = i,vec.pop_back();
			vec.pb(i);
		}
		vec.clear();
		fir(i,1,n){
    
    
			while(vec.size() && a[i] < a[vec.back()]) rmin[vec.back()] = i,vec.pop_back();
			vec.pb(i);
		}
		vec.clear();
		afir(i,n,1){
    
    
			while(vec.size() && a[i] < a[vec.back()]) lmin[vec.back()] = i,vec.pop_back();
			vec.pb(i);
		}
		bool f = 0;
		int x,y,z;
		fir(i,1,tn){
    
    
			if((int)tmp[i].size() < 3) continue;
			int x1 = tmp[i][0],x2 = tmp[i].back();
			if(lmax[x1] || rmax[x2]) continue;
			int r1 = rmax[x1],l1 = lmax[x2];
			fir(j,1,(int)tmp[i].size()-2){
    
    
				int x3 = tmp[i][j];
				int l2 = lmin[x3],r2 = rmin[x3];
				if((!r1 || l2-r1 <= 0) && (!r2 || l1-r2 <= 0)){
    
    
					f = 1;
					if(!r1) x = x3-1;
					else x = min(r1-1,x3-1);
					z = max(l1+1,x3+1);
					z = n-z+1;
					y = n-x-z;
					break;
				}
			}
			if(f) break;
		}
		if(!f){
    
    
			cout << "NO\n";
			continue;
		}
		cout << "Yes\n" << x << " " << y << " " << z << "\n";

	}
	
	return 0;
}	

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/110642847