【题目】
对于一个
令
举例来说,如果
下列程序读入了排列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include <iostream> using namespace std; const int N = 100010; int n; int L[N], R[N], a[N]; int main() { cin >> n; for ( int i = 1; i <= n; ++i) { int x; cin >> x; ① ; } for ( int i = 1; i <= n; ++i) { R[i] = ② ; L[i] = i - 1; } for ( int i = 1; i <= n; ++i) { L[ ③ ] = L[a[i]]; R[L[a[i]]] = R[ ④ ]; } for ( int i = 1; i <= n; ++i) { cout << ⑤ << " " ; } cout << endl; return 0; } |
【解析】
先说说这道题怎么拿链表解决。
先找到最小的元素,是第1位的1,它右边不论是几都肯定比它大,所以这一位的答案就是右侧的第2位。
此时把它从链表中删除,让前一位直接指向后一位。
再在链表中找到最小的元素,是第4位的2,它右边不论是几都比它大,所以这一位的答案是第5位。
再从链表中把2删除,让前一位指向后一位。
继续这个过程,找到最小的元素是第5位的3,它右侧的元素肯定比它大,因此这一位的答案是第6位。
然后从链表中把3删除,让前一位指向后一位。
继续,最小的元素是第3位的4,它右侧的元素(第6位)比它大,这一位答案是6。
从链表中删除4。
最后只剩第2位的5,右侧(第6位)比它大,这一位答案是6。把它删除后,整个操作结束。
最终的答案就是过程中记录下的数据,第1位是2,第4位是5,第5位是6,第3位是6,第2位是6,
即答案数组2 6 6 5 6。
程序用的是双向链表,
这样有什么好处呢?副产品会更多。
最终不止知道每个元素后面比它大的第一个元素在哪,还能知道前面比它大的第一个元素在哪。
第2个for循环,显然它是先把ii对应到a[i],再对应到L和R数组,为什么呢?为了去掉每轮都要先寻找最小值的过程。先存一下第1小、第2小、第3小……的值依次出现在哪儿,每轮就能直那一位。
第1题:
即最小的数出现在第1位,第2小在第4位……
第2题:
L记录前面第一个更大值的位置
R记录后面第一个更大值的位置
根据最值更新链表的过程,定位到当前的最小值后,就要从双向链表中将它删除。
要让前一位和后一位直接互相指向,用自己的前一位更新后一位的前一位,用自己的后一位更新前一位的后一位。
第3题:
第4题:
我们假定位置
第5题: