Codeforces Round #686 (Div. 3)F

题目链接
这一题看完的唯一想法就是RMQ其他别无想法,但是仔细一想,如果是1到n中只放一个点然后来查找的话,然后要查找是否存在一个点为分界线使得左边的最小值等于右边的嘴大值时是满足单调性的,因为越往右移动最小值也越小,最大值也越小所以是满足单调性的,这里是中间有两个点,所以我们可以固定左边界,然后二分再查找是否有满足题意的点。不过二分的边界情况有点难搞,仔细理一下就好了。

//#include<bits/stdc++.h>
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define ull unsigned long long
#define se second
#define lson (rt<<1)
#define rson (rt<<1|1)
#define endl "\n"
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 4e5 + 10;
const int maxm = 1e4 + 50;
const double eps = 1e-7;
const ll inf = 0x3f3f3f3f;
const ll  lnf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
int q[maxn], n, dpmax[maxn][33], dpmin[maxn][33];
void rmq()
{
	for (int i = 1; i <= n; i++)
	{
		dpmax[i][0] = q[i];
		dpmin[i][0] = q[i];
	}
	for (int j = 1; (1 << j) <= n; j++)
	{
		for (int i = 1; i + (1 << j) - 1 <= n; i++)//修改了i=0
		{
			dpmax[i][j] = max(dpmax[i][j - 1], dpmax[i + (1 << (j - 1))][j - 1]);
			dpmin[i][j] = min(dpmin[i][j - 1], dpmin[i + (1 << (j - 1))][j - 1]);
		}
	}
}
int query_min(int l, int r)
{
	int k = log2(r - l + 1);
	return min(dpmin[l][k], dpmin[r - (1 << k) + 1][k]);
}
int query_max(int l, int r)
{
	int k = log2(r - l + 1);
	return max(dpmax[l][k], dpmax[r - (1 << k) + 1][k]);
}
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &q[i]);
		}
		rmq();
		bool xx = false;
		for (int i = 1; i <= n - 2; i++)
		{
			bool flage = false;
			int l = i + 1, r = n - 1;
			int ans;
			int lma = query_max(1, i);
			while (r >= l)
			{
				int mid = (l + r) >> 1;
				int mi = query_min(i + 1, mid);
				if (mi == lma)
				{
					int rma = query_max(mid + 1, n);
					if (rma == mi)
					{
						ans = mid;
						flage = true;
						break;
					}
					else if (mi > rma)//注意最大值是哪个
					{
						r = mid - 1;
					}
					else
					{
						l = mid + 1;
					}
				}
				else
				{
					if (mi > lma)//注意最大值是哪个
					{
						l = mid + 1;
					}
					else
					{
						r = mid - 1;
					}
				}
			}
			if (flage)
			{
				xx = true;
				printf("YES\n");
				printf("%d %d %d\n", i, ans - i, n - ans);//l=i,y+x=ans,x+y+z=n;
				break;
			}
		
		}
		if (!xx)
		{
			printf("NO\n");
		}
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值