1. 程式人生 > 實用技巧 >【謎一樣的牛】題解

【謎一樣的牛】題解

題目描述


題目描述
有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 左右,就可以過了。