传送门
题目大意:给一个数组,问能否把数组分为三段区间满足:
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;
}