1. 程式人生 > >The King’sUps and Downs(DP)

The King’sUps and Downs(DP)

The King’sUps and Downs

Time Limit: 2000/1000 MS(Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 758    Accepted Submission(s): 539

Problem Description

The king has guards of alldifferent heights. Rather than line them up in increasing or decreasing heightorder, he wants to line them up so each guard is either shorter than the guardsnext to him or taller than the guards next to him (so the heights go up anddown along the line). For example, seven guards of heights 160, 162, 164, 166,168, 170 and 172 cm. 

The king wants to know how many guards he needs so he can have a different upand down order at each changing of the guard for rest of his reign. To be ableto do this, he needs to know for a given number of guards, n, how manydifferent up and down orders there are:

For example, if there are four guards: 1, 2, 3,4 can be arrange as:

1324, 2143, 3142, 2314, 3412, 4231, 4132, 2413, 3241, 1423

For this problem, you will write a program that takes as input a positiveinteger n, the number of guards and returns the number of up and down ordersfor n guards of differing heights.

Input

The first line of inputcontains a single integer P, (1 <= P <= 1000), which is the number ofdata sets that follow. Each data set consists of single line of inputcontaining two integers. The first integer, D is the data set number. Thesecond integer, n (1 <= n <= 20), is the number of guards of differingheights.

Output

For each data set there is oneline of output. It contains the data set number (D) followed by a single space,followed by the number of up and down orders for the n guards.

Sample Input

4

1 1

2 3

3 4

4 20

Sample Output

1 1

2 4

3 10

4 740742376475050

【題意】

身高各不相同的n個人(n<=20)排成一隊,要求他們的身高依次為高低高或者低高低的交錯排列,求有多少種排列方法。

【思路】

   假設這n個人身高為1,2,3…,n,那麼我們假設前n-1個人已經排好,把這個身高最高為n的人加入隊裡,如果我們把高看成1,低看成0,構成的排列看成一個01串,那麼在他前面的子序列一定以10結尾,後面的子序列一定以01開頭。所以設dp(n)為n個人時的解,f[i][0]為長度為i且結尾是10的情況數,f[i][1]是長度為i且開頭是01的情況數。則dp[n]=sum{f[i][0]*f[n-1-i]*c[n-1][i]|0<=i<=n},c[n-1][i]是從n-1個人中挑出i個的組合數。注意到開頭為01的話如果把它顛倒那麼就一定以10結尾,所以f[i][0]=f[i][1]=dp[i],這樣就可以遞推答案了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 20;

int a, n;
ll c[maxn + 5][maxn + 5];
ll f[maxn + 5][2], dp[maxn + 5];

void init() {
	c[0][0] = 1;
	for (int i = 1; i <= maxn; ++i) {
		c[i][0] = c[i][i] = 1;
		for (int j = 1; j < i; ++j) {
			c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
		}
	}
	
	dp[1] = 1;
	f[0][0] = f[0][1] = 1;
	f[1][0] = f[1][1] = 1;
	for (int i = 2; i <= maxn; ++i) {
		dp[i] = 0;
		for (int j = 0; j <= i; ++j) {
			dp[i] += f[j][0]*f[i-1-j][1]*c[i - 1][j];
		}
		f[i][0] = f[i][1] = dp[i] / 2;
	}
}

int main() {
	init();
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &a, &n);
		printf("%d %lld\n", a, dp[n]);
	}
	return 0;
}