Codeforces Round #637 (Div. 2) ——C. Nastya and Strange Generator 题解

题目链接:https://codeforces.com/contest/1341/problem/C
Codeforces Round #637 (Div. 2) ——C. Nastya and Strange Generator 题解_第1张图片
Codeforces Round #637 (Div. 2) ——C. Nastya and Strange Generator 题解_第2张图片
Codeforces Round #637 (Div. 2) ——C. Nastya and Strange Generator 题解_第3张图片
这是一道看懂了题也得想半天的思维题,捋一下思路先
(1)给定n,要把1-n的n个数安排到数组的1-n位置,安排的过程如下
(2)先计算 r 数组,对于 r[i] 必须满足 r[i] >= i 且 r[i]没有被占用,换句话说,每一个元素必须大于等于当前对应的下标,且这个元素的位置还空着
(3)再计算count数组,需要满足count[i] = i,换句话说就是计算 r 数组中有几个数的值等于当前下标。

还是乱?我们来接着捣鼓
比如 n = 5,最开始数组空着
(1)第一步求 r 数组,我们看第一个元素必须满足 r[1] >= 1,正好第一个位置是空的,那么 r[1] = 1即可,同理 r[2] >= 2,第二个位置是空的,那么r[2] = 2…以此类推 r = [1, 2, 3, 4, 5]
(2)第二步求 count 数组,先求 count[1],就是看 r 数组有多少个元素值等于1,发现只有 r[1] = 1,所以count[1] = 1,同理得到 count = [1, 1, 1, 1, 1]
(3)题目说了选 count 中最大的值 对应的位置作为下一个元素的填充位置,那么此时是随便填的,我们假设选第一个位置,看看会怎么样
(4)第二轮求 r 数组,这里与(1)的不同在于,第一个元素 r[1] >= 1,但此时第一个位置被填充了,所以 r[1] = 2(因为要找最小的未填充位置),后面的r[2-5]是不受影响的,所以 r = [2, 2, 3, 4, 5]
(5)再求 count 数组:count = [0, 2, 1, 1, 1],此时最大的是位置2,因为 r 数组中出现了两次 2. 所以第二个元素的位置必须是 2

有发现什么神奇的事情吗?现在如果要求第三个元素的位置,是不是有 r = [3, 3, 3, 4, 5], count = [0, 0, 3, 1, 1],是不是必须放在第三个位置?

这就是说,如果一个元素放在了第k个位置,那么下一个元素定位时,r数组中第 k 个元素由于被占位只能后移一位变成 k + 1,而第 k + 1个元素的值也为 k + 1,这就势必导致count数组中 k + 1位置的值是最大的,所以只能定位在 k + 1。

那如果某一个元素放在了当前可放的最后一个位置,会发生什么呢?我们会发现并不会影响 r 和 count 数组的前面元素的值,所以如果某一个元素的位置是数组空闲的最后一个位置,那么其下一个元素可以任选位置放入。

代码如下:

#include 
using namespace std;
 
int main() {
	int t;
	cin >> t;
	while(t--) {
		int p[100005] = {0};
		bool vis[100005];	//标识数组中每一个位置是否占用
		int n;
		cin >> n;
		for(int i = 1; i <= n; i++) {
			cin >> p[i];
		}
		fill(vis, vis + n, 1);	//所有位置设置为未占用
		bool xianzhi = true;	//限制标识符,标识下一个元素是否受定位限制
		bool res = true;
		int top = n;			//存放当前数组最后一个未占用位置
		if(p[1] == top) {		//特判,第一个元素是否为top
			xianzhi = false;	//若为top,下一个元素位置不受影响可任选
			top = n - 1;		//更新top
		}
		vis[p[1]] = false;
		for(int i = 2; i <= n; i++) {
			vis[p[i]] = false;
//			cout << "限制:" << xianzhi << ", top = " << top  << ", p[i] = " << p[i] << endl;
			if(xianzhi) {
				if(p[i] != p[i - 1] + 1) {
					cout << "No" << endl;	// 受限制且不满足定位条件
					res = false;
					break;
				}
			}
			if(p[i] == top) {
				xianzhi = false;
				while(vis[top] != true) {
					top--;		//更新top:找到当前最后一个未占用位置
				}
			} else {
				xianzhi = true;
			}
		}
		if(res) {
			cout << "Yes" << endl;
		}
	}
	return 0;
}

你可能感兴趣的:(CF)