问题来源
BYVoid魔兽世界模拟赛
【问题描述】
蒙提在暴风城与铁炉堡之间的地铁站中工作了许多年,除了每天抓一些矿道老鼠外,没有其他的变化。然而最近地铁站终于要扩建了,因为侏儒们攻克了建设长距离穿海隧道的技术难题,矮人们制造的炸药威力也有了很大的增强。于是,联盟决定修建通往诺森德的地铁。拥有常年的地铁站工作经验的蒙提被派往了新的线路上,他的工作是进行地铁重组。
如上图,在左边部分停靠着N节车厢,从右向左标号依次为1、2、……、N。中间有一个停车轨道,这个轨道上最多只能同时停放P节车厢。现在需要将左边轨道上的车厢驶入右边的轨道。每节车厢必须进入一次停车轨道进行检修,然后才能去右边的轨道。侏儒制造的每节车厢都有完整的动力装置,不需要依赖车头的带动。对于一个给定的停车轨道的大小P和左边轨道的车厢的数目N,蒙提想知道,这些车厢到右边轨道以后,有多少种不同的排列顺序。
【输入格式】
第1行:两个整数N,P。
【输出格式】
第1行:一个整数a,为排列顺序数除以4096的余数。
【输入样例】
3 2
【输出样例】
4
【数据说明】
对于70%的数据 1 <= N <= 500 1 <= P <= 300 对于100%的数据 1 <= N <= 2000 1 <= P <= 2000
分析
以栈为基础的递推公式是这道题目中唯一的难点,因为代码中有足够多的注释我就不再作过多解释了。
1 /* 2 ID: ringxu97 3 LANG: C++ 4 TASK: subway 5 SOLUTION: 递推 6 */ 7 #include<cstdio> 8 #include<cstring> 9 #include<iostream> 10 #include<cmath> 11 #include<cstdlib> 12 #include<algorithm> 13 #include<vector> 14 #include<stack> 15 #include<queue> 16 using namespace std; 17 //F[i][j]表示左边有i个 栈中有j个时的状态 最终状态为F[0][0] 18 //F[i][j]=F[i+1][i-1]+F[i][i+1] 19 const int maxn=2000+10; 20 const int MOD=4096; 21 int n,p; 22 int F[maxn][maxn]; 23 void solve() 24 { 25 for(int i=n-1;i>=0;--i) 26 for(int j=min(p,n-i);j>=0;--j) 27 { 28 F[i][j]=F[i][j+1]%MOD;; 29 if(j>0)F[i][j]+=F[i+1][j-1]%MOD;; 30 F[i][j]=F[i][j]%MOD; 31 } 32 } 33 int main() 34 { 35 freopen("subway.in", "r", stdin); 36 freopen("subway.out", "w", stdout); 37 scanf("%d%d",&n,&p); 38 F[n][0]=1; 39 solve(); 40 printf("%d ",F[0][0]%MOD); 41 return 0; 42 }