题解 P1044 【栈】

· · 题解

[ 更好的阅读体验 ]

[ 原题面 ]

第零部分 —— 阅读题目

- 明显,每个数只能进出栈一次,进出栈共 $ 2n $ 次 --- ### 第一部分 —— 开始分析 - 这看起来很像卡特兰数,但是,这篇题解不是来教你卡特兰数的(卡特兰数的题解,似乎进不了题解界面 $ QAQ $ ) - 我们今天要用 **暴力+剪枝+卡常** 过了这道题 - 我们发现暴力的代码似乎很好写,时间复杂度也没那么高,大概 $ O(2^{2n} ) $ - $ Therefore ,$ 一份纯暴力的代码就出现了: ```cpp //#pragma GCC optimize ("O2") //#pragma GCC optimize ("O3") //#pragma GCC optimize ("Ofast") #include <bits/stdc++.h> int n,Ans; inline void Doit(const int x,const int y) { if (y == n) { //边界条件,所有数都出栈了 ++ Ans; return; } if (x+y < n) Doit(x+1,y); //递归操作1,条件:还有数没有入过栈 if (x) Doit(x-1,y+1); //递归操作2,条件:栈里还有数 } signed main() { scanf("%d",&n); Doit(0,0); printf("%d\n",Ans); } ``` - 代码中的 $ x $ 表示栈里面有 $ x $ 个数, - $ y $ 表示出栈了 $ y $ 个数 - 边界条件就是所有数都出栈

第二部分 —— 深入思考

优化1:

优化2:

常数优化:

- 经过上述优化,在加上洛谷的玄学 $ O2 $,我们成功把时间控制在 $ 0.5Sec $ 以内,足以过掉此题,若没有 $ O2 $ ,时间大约在 $ 0.9Sec $左右,有些吃力,可也能通过 ### 第三部分 —— 代码实现 - 我相信,大家都能写出这道题的代码(毕竟已经出示了重要优化的核心代码了),但还是放上一份本人的代码吧(自认为码风不错 $ QuQ $) ```cpp //#pragma GCC optimize ("O2") //#pragma GCC optimize ("O3") //#pragma GCC optimize ("Ofast") #include <bits/stdc++.h> int n,Ans; inline void Doit(const int x,const int y) { if (x+y == n-1) { //优化1+优化2 Ans += x+1; //优化2 return; } Doit(x+1,y), //常数优化 (x) && (Doit(x-1,y+1),0); //常数优化 } signed main() { scanf("%d",&n); Doit(n>1,0); //特判n<=1 printf("%d\n",Ans); } ``` ### 第四部分 —— 延伸阅读① - 前面讲过 $ C++ $ 的短路运算符 &&,但什么是短路运算符呢? - 短路,就是说形如 (表达式)&&(表达式) 的形式,如若前者为假,那么是不是不需要计算后者,就可以知道,这整个表达式的值为假 - 当然,后者必须是一个表达式才可以进行这种运算,当我们发现我们要执行的语句为一个无返回值的 $ void $ 函数时,我们可用逗号,强制加上一个表达式作为需要,同时,这个表达式可以简单到 $ 0 $ 和 $ 1 $ 这样的纯数值 #### 第五部分 —— 后记 - 不知不觉就写了这么多了呢,如果这篇题解中有任何错误,欢迎在评论区,或私信支出,若是你觉的这篇题解还不错,那就点一个赞吧 (ヽ(”`▽´)ノ )