『妙不可言系列6』CF641D Orac and Medians

P r o b l e m \mathrm{Problem} Problem

Slime has a sequence of positive integers a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an .

In one operation Orac can choose an arbitrary subsegment [ l … r ] [l \ldots r] [lr] of this sequence and replace all values a l , a l + 1 , … , a r a_l, a_{l + 1}, \ldots, a_r al,al+1,,ar to the value of median of { a l , a l + 1 , … , a r } \{a_l, a_{l + 1}, \ldots, a_r\} {al,al+1,,ar} .

In this problem, for the integer multiset s s s , the median of s s s is equal to the ⌊ ∣ s ∣ + 1 2 ⌋ \lfloor \frac{|s|+1}{2}\rfloor 2s+1 -th smallest number in it. For example, the median of { 1 , 4 , 4 , 6 , 5 } \{1,4,4,6,5\} {1,4,4,6,5} is 4 4 4 , and the median of { 1 , 7 , 5 , 8 } \{1,7,5,8\} {1,7,5,8} is 5 5 5 .

Slime wants Orac to make a 1 = a 2 = … = a n = k a_1 = a_2 = \ldots = a_n = k a1=a2==an=k using these operations.

Orac thinks that it is impossible, and he does not want to waste his time, so he decided to ask you if it is possible to satisfy the Slime's requirement, he may ask you these questions several times.

T r a n s l a t e \mathrm{Translate} Translate

询问 a 1 , a 2 , ⋯ a n a_1,a_2,\cdots a_n a1,a2,an能否通过若干次将任意区间全部赋值为其中位数这个操作,来使得整个序列全部变为 k k k。(中位数指第 ⌊ ∣ s ∣ + 1 2 ⌋ \lfloor \frac {∣s∣+1} 2 \rfloor 2s+1小的数)

多次询问,每次第一行两个整数, n n n k k k;第二行 n n n个整数, a 1 , a 2 , ⋯ a n a_1,a_2,\cdots a_n a1,a2,an

数据范围: 1 ≤ n ≤ 1 0 5 , 1 ≤ k ≤ 1 0 9 , 1 ≤ a i ≤ 1 0 9 1 \le n \le 10^5,1 \le k \le 10^9,1 \le a_i \le 10^9 1n105,1k109,1ai109,并保证所有询问中 n n n的和不超过 1 0 5 10^5 105

S o l u t i o n \mathrm{Solution} Solution

我们观察一下让所有数字变成 k k k的条件:

  • 若存在 a i = k a_i=k ai=k时满足 a i ≤ a i − 1 a_i \le a_{i-1} aiai1或者 a i ≤ a i + 1 a_i \le a_{i+1} aiai+1时,一定存在合法方案。
  • 因为每一次可以将 a i + 1 a_{i+1} ai+1或者 a i − 1 a_{i-1} ai1变成 k k k,这样就存在连续的两个 k k k,第三个数字加入无论如何答案都是 k k k。因此我们便可以将所有数字都变成 k k k

那么如何才能让 a i a_i ai相邻的数字比 k k k大呢?

  • 若存在连续的三个数中有两个大于等于 k k k,那么所有数都可以转变为大于等于 k k k的数字。

C o d e \mathrm{Code} Code

#include <bits/stdc++.h>

using namespace std;
const int N = 1e6;

int n, k;
int a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (c < '0' || c > '9') w |= c == '-', c = getchar();
	while (c >= '0' && c <= '9') s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

void work(void)
{
	int tag = 0;
	n = read(), k = read();
	for (int i=1;i<=n;++i) {
		a[i] = read();
		if (a[i] == k) tag = 1;
	}	
	if (tag == 0) {
		puts("no");
		return;
	}
	if (n == 1) {
		puts("yes");
		return;
	}
	for (int i=1;i<n;++i) 
		if (a[i] >= k && a[i+1] >= k) {
			puts("yes");
			return;
		}
	for (int i=1;i<n-1;++i)
		if (a[i] >= k && a[i+2] >= k) {
			puts("yes");
			return;
		}
	puts("no");
	return;
}

int main(void)
{
	int T = read();
	while (T --) work();
}   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值