codeforces Round 616 Div2 B - Array Sharpening

题目大意:

T组样例,每组样例有一个n个数字的序列,(长度为n的数组),每次可以选择序列中任意一个大于0的数字操作,使其自减1

(a = a - 1)

问最终是否可以形成一个序列,满足对其中某一个位置k而言

a_{1}< a_{2}<a_{3}<\cdot \cdot \cdot <a_{k}>a_{k-1}>a_{k-2}>\cdot \cdot \cdot >a_{n}

当然,如果序列是严格递增或者递减的也是可行的

思路

说实话,题目不难,但是我感觉思路很巧妙,就记录一下吧

首先考虑最简单的情况,递增或者递减,可以先处理出来所有的位置上的数字可否在当前位置使前面(或后面)的数字完成递增(或递减),可以用两个数组c1,c2表示可行否。

如果一个位置递增可行,条件是,首先前面的那个数字递增可行,然后就是当前位置的数字大小要求,因为是严格递增,对于第2个数字而言,要想完成递增前面至少是一个数字0,那么自己就必须大于等于1,同理,递减也是一样

但是递增是从1到n,递减就是从n到1递减了

如果递增到最后一个数字依然可行,说明整个序列可以转换为递增,或者,如果递减到第一个数依然可行,说明整个序列可以转换为递减的。那就一定可行了。

对于中间的正态分布形状的序列而言,可以通过上面的两个数组求解

对于其中某一个位置k,如果c1[k] = true and c2[k] = true,说明当前位置前面可以完成一次严格递增(包含自身),并且后面可以完成一次严格递减(包含自身),说明已经可以形成上述形状的序列了,只需要遍历一边1到n,判断c1[i] 和 c2[i]是否可以同时为true,只要有一个满足即可完成。

不用纠结与a[k]位置的值,满足前面递增后面递减是否会不相等,既然可以完成上述操作,说明可以转换为下述序列的样子

1 < 2 < 3 <\cdot \cdot \cdot <k>k-1>k-2>\cdot \cdot \cdot >1

最后全都转换成这样总一定可行了吧

#include <bits/stdc++.h>
using namespace std;
const int N = 300100;
int arr[N];
#define mem(a, b) memset(a, b, sizeof a)
#pragma warning (disable:6031)
#pragma warning (disable:4996)
int t, n;
bool c1[N], c2[N];
int main()
{
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		bool f1 = 1, f2 = 1;
		bool f3 = 1;
		for (int i = 1; i <= n; i++)scanf("%d", arr + i);
		mem(c1, 0);// 初始均不行
		mem(c2, 0);
		c1[1] = 1;
		// c1记录递增
		for (int i = 2; i <= n; i++) {
			if (c1[i - 1] && arr[i] >= i - 1) {
				c1[i] = 1;
				// 如果上一个数字可行,并且当前数字大小可行,即为可行
			}
			else {
				break;
				// 如果当前数字不行,后面的都不会行
			}
		}
		// 同上
		c2[n] = 1;
		for (int i = n - 1; i >= 1; i--) {
			if (c2[i + 1] && arr[i] >= n - i) {
				c2[i] = 1;
			}
			else break;
		}
		f1 = c1[n];
		f2 = c2[1];
		f3 = 0;
		for (int i = 1; i <= n; i++) {
			if (c1[i] && c2[i]) {
				f3 = 1;
			}
		}
		// f1 表示序列可否转为全部递增
		// f2 表示序列可否转为全部递减
		// f3 表示能否形成正态分布形状的序列
		if (f1 || f2 || f3)puts("Yes");
		else puts("No");
	}
	return 0;
}
发布了165 篇原创文章 · 获赞 11 · 访问量 9636

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/104153608
今日推荐