HDOJ4489——国王的沉浮

HDOJ4489——国王的沉浮

问题描述

HDOJ4489
有n个身高递增的人,使他们高低高低排列,求一共有多少种排法。
1.png
或者
2.png

Input

The first line of input contains a single integer P, (1 <= P <= 1000), which is the number of data sets that follow. Each data set consists of single line of input containing two integers. The first integer, D is the data set number. The second integer, n (1 <= n <= 20), is the number of guards of differing heights.

Output

For each data set there is one line 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个人an一定比前面n-1个人都高。将他插入前n-1个人组成的队列之中,使得新的队列依旧满足题意,那么必须满足: an 的前面为下降的,an 的后面为上升的。如图。
3.png
设an在n个人的队列中的位置为i,则他左边有i-1个人,他右边有n-i个人。容易推出这个时候所有的排列方法为$\frac{dp[i-1]}{2} \frac{dp[n-i]}{2} C{n-1}^{i-1}$
解释一下这个式子:左边i-1个人排出最右边为下降的队列的方法是总方法的一半,右边n-i个人同理,证明略。
那么n个人的总排序方法就是$\sum^{n}
{i=1} \frac{dp[i-1]}{2} \frac{dp[n-i]}{2} C_{n-1}^{i-1} $

代码实现

#include<cstdio>
#include<cstring>
typedef long long LL;
LL c[21][21];
LL dp[21];
void pre()
{
  int i,j;
  /*求出C[0][0]到C[20][20]的组合数*/
  for(i=0;i<=20;i++)  c[0][i] = c[i][i] = 1;
  for(i=2;i<=20;i++)
    for(j=1;j<i;j++) c[j][i] = c[j-1][i-1] + c[j][i-1];
  dp[0] = dp[1] = 1;
  for(i=2;i<=20;i++)
  {
    for(j=1;j<=i;j++)
    {
      dp[i] += c[j-1][i-1] * ((j-1<=1) ? 1 : dp[j-1] / 2) * ((i-j<=1) ? 1 : dp[i-j] / 2);
    }
  }
}

int main()
{
  int i,set,kase,num;
  pre();
  scanf("%d",&kase);
  while(kase--)
  {
    scanf("%d%d",&set,&num);
    printf("%d %I64d\n",set,dp[num]);
  }
}
... ... ...