复制代码

【谜一样的牛】题解

题目描述


题目描述
有n头奶牛,已知它们的身高为 1~n 且各不相同,但不知道每头奶牛的具体身高。
现在这n头奶牛站成一列,已知第i头牛前面有Ai头牛比它低,求每头奶牛的身高。


输入格式
第1行:输入整数n。
第2..n行:每行输入一个整数Ai,第i行表示第i头牛前面有Ai头牛比它低。 (注意:因为第1头牛前面没有牛,所以并没有将它列出)


输出格式
输出包含n行,每行输出一个整数表示牛的身高。
第i行输出第i头牛的身高。


样例输入
5
1
2
1
0


样例输出


2
4
5
3
1


分析

首先,这道题我们采用倒推的思想。
由于题目告诉我们,所有牛的身高是 1 ~ n, 所以我先用一个优先队列(等会说为什么)来保存所有还没有确定是哪头牛身高的值,初始当然是把所有值存进去。
我们设当前序列的最后一头牛的前面有 x 头比他矮。那么当他的身高是 y 时, 那么他前面比他矮的牛一定是现在序列中所有身高比 y 小的所有(因为他在最后)(显而易见吧),那么我们想要他前面有 x 头牛比他矮,我们就需要他是当前序列之中 x + 1 小的值(优先队列就是为了找最小)。我们在找出这个值之后,我们就把他从优先队列之中弹出(因为他已经在这个位置,因为是从后往前面找,所以他在这里就不会影响他的前面一个值了,就把他弹出),并储存答案。

代码

#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;

const int MAXN = 1e5 + 5;

queue <int> q2;
priority_queue <int, vector <int>, greater<int> > q;

int a[MAXN];
int ans[MAXN];

void read(int &x) {
	x = 0; 
	int f = 1;
	char s = getchar(); 
	while (s > '9' || s < '0') { 
		if (s == '-') f = -1; 
		s = getchar(); 
	}
	while (s >= '0' && s <= '9') { 
		x = (x << 3) + (x << 1) + (s - '0');
		s = getchar(); 
	}
	x *= f;
}

int main () {
	int n;
	read(n);
	q.push(1); 
	for (int i = 2; i <= n; i++) {
		read (a[i]); 
		q.push(i); 
	}
	for (int i = n; i >= 2; i--) {
//		printf ("+%d+ ", a[i]);
		while (a[i]--) {
			q2.push(q.top()); 
			q.pop(); 
		}
		ans[i] = q.top(); 
		q.pop(); 
		while (!q2.empty()) {
			q.push(q2.front()); 
			q2.pop(); 
		}
	}
	printf ("%d\n", q.top());
	for (int i = 2; i <= n; i++) {
		printf ("%d\n", ans[i]);
	}
	return 0;
}

当然大家也看到了,这个代码的时间复杂度是很高的,所以我们呢就只拿到了 86分,所以就想到了优化。

双端队列

如下:

#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;

const int MAXN = 1e5 + 5;

deque <int> q2;
deque <int> q;

int a[MAXN];
int ans[MAXN];

void read(int &x) {
	x = 0; 
	int f = 1;
	char s = getchar(); 
	while (s > '9' || s < '0') { 
		if (s == '-') f = -1; 
		s = getchar(); 
	}
	while (s >= '0' && s <= '9') { 
		x = (x << 3) + (x << 1) + (s - '0');
		s = getchar(); 
	}
	x *= f;
}

int main () {
	int n;
	read(n);
	q.push_back(1); 
	for (int i = 2; i <= n; i++) {
		read (a[i]); 
		q.push_back(i); 
	}
	for (int i = n; i >= 2; i--) {
//		printf ("+%d+ ", a[i]);
		while (a[i]--) {
			q2.push_back(q.front()); 
			q.pop_front(); 
		}
		ans[i] = q.front(); 
		q.pop_front(); 
		while (!q2.empty()) {
			q.push_front(q2.back()); 
			q2.pop_back(); 
		}
	}
	printf ("%d\n", q.front());
	for (int i = 2; i <= n; i++) {
		printf ("%d\n", ans[i]);
	}
	return 0;
}

这样大大优化了时间复杂度,大概为 245 ms 左右,就可以过了。

posted @ 2020-08-23 20:53  cqbz_yanglin  阅读(453)  评论(2)    收藏  举报