专栏文章

题解:P1044 [NOIP 2003 普及组] 栈

P1044题解参与者 44已保存评论 50

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
50 条
当前快照
1 份
快照标识符
@mipuo954
此快照首次捕获于
2025/12/03 18:14
3 个月前
此快照最后确认于
2025/12/03 18:14
3 个月前
查看原文

思路

假设我们用一个函数 C(x,y)\operatorname{C}(x,y) 表示:
  • xx:当前还未入栈的数字个数。
  • yy:当前栈中的数字个数。
我们的目标是计算 C(n,0)\operatorname{C}(n,0),即从 nn 个数字开始,生成输出序列的方式。
在任何状态下,我们有两种选择:
  • push 操作:如果还有数字可以入栈(即 x>0x>0),我们可以将一个数字从输入序列中移入栈中。这会减少未入栈的数字个数 xx,同时增加栈中的数字个数 yy。因此,该操作对应于 C(x1,y+1)\operatorname{C}(x-1,y+1)
  • pop 操作:如果栈中有数字可以出栈(即 y>0y>0),我们可以将栈顶数字移出到输出序列中。这不会改变未入栈的数字个数 xx,但会减少栈中的数字个数 yy。因此,该操作对应于 C(x,y1)\operatorname{C}(x,y-1)
递归的边界条件是:当 x=0y=nx=0 \land y=n 时,表示所有数字已成功输出为一个序列,这算作一种有效方式,返回 11;其他不合法状态(如 x<0y>nx<0 \lor y>n)返回 00
递归太慢,所以我们可以用 DP,转移方程是: fx,y=fx1,y+1+fx,y1f_{x,y}=f_{x-1,y+1}+f_{x,y-1}

Code

CPP
#include<bits/stdc++.h>
using namespace std;
int f[20][20],n;
int main(){
	cin>>n;
	for(int x=0;x<=n;x++){
		for(int y=0;y<=n;y++){
			if(!x) f[x][y]=1;
			else if(!y) f[x][y]=f[x-1][y+1];
			else f[x][y]=f[x-1][y+1]+f[x][y-1];
		}
	}
	cout<<f[n][0];
}
有问题请指出!
感谢 NJYgocrazy指出一个小错误。

评论

50 条评论,欢迎与作者交流。

正在加载评论...