Permutation

                                                                      Permutation

题目链接:http://soj.me/show_problem.php?pid=1002&cid=1035

Description

Permutation plays a very important role in Combinatorics. 

For example, 1 2 3 4 5 and 1 3 5 4 2 are both 5-permutations. 

As everyone's known, the number of n-permutations is n!. 

According to their magnitude relatives, if we insert the symbols '<' or '>' between every pairs of consecutive numbers of a permutation, we can get the permutation with symbols. 

For example, 1 2 3 4 5 can be changed to 1<2<3<4<5, 

1 3 5 4 2 can be changed to 1<3<5>4>2. 

Now it's your task to calculate the number of n-permutations with k '<' symbols. 

Maybe you don't like large numbers, so you should just give the result mod 2007. 

Input

Input may contain multiple test cases. 

Each test case is a line contains two integers n and k.0<n<=100 and 0<=k<=100. 

The input will terminated by EOF. 

Output

The nonnegative integer result mod 2007 on a line. 

Sample Input
 Copy sample input to clipboard
5 2
Sample Output
66

题目描述:输入n,k,在数字1~n的全排列中,求满足有k个小于号的排列方案数。
分析:p[i][j]:表示i个数字,k个小于号的方案数。
          样例中,5个数,2个小于号。用动态规划的思想,将问题逐步拆分为小的问题。
          假如已经知道了1-4的排列,把5加上去,可能的情况是: 
         (1)  5在最前面,这样会在原来的状态下多加了一个 >; 即:5>xxxxx
         (2)  5在最后面,这样就多加了一个<;即:xxxxx<5;
         (3)  5在中间,会出现 <5> 的情况:
                    如果该处本来就是<,加了5以后,会多了一个>;如果本来是>,加了5就多了<;


         所以,状态转移方程:
         if(j==i-1|| j==0)    p[i][j]=1; //都只有一种情况,全是<或全是>
         else 
              p[i][j]=(j+1)*p[i-1][j] + (i-j)*p[i-1][j-1];
        
           (j+1)*p[i-1][j]: 表示原来i-1个数里面,已经有了j个<,插入最后一个数时,只需要多一个大于号,可插入的地方有:数列的开头,以及原来是小于号的地方,共有j+1个位置可以插入最后一个数;
           (i-j)*p[i-1][j-1]:表示原来i-1个数里面,有j-1个<,还需要增加一个<,可选的位置有:数列的最后,以及原来是大于号的位置。数列中间共有i-2个位置,减去是小于号的j-1的位置,还有i-1-j个,再加上数列的最后一个位置,所以共有i-j个位置可以插入最后一个数;


注意取模;

代码如下:

#include<iostream>
#include<cstring>
using namespace std;
int p[101][101];

void check()
{  
  p[0][0]=0;
  for(int i=1;i<101;i++)
  {
     p[i][0]=1;
     for(int j=1;j<i;j++)
     {
      if(j==i-1) p[i][j]=1;
      else  p[i][j] = (((j+1)*p[i-1][j])%2007 + ((i-j)*p[i-1][j-1])% 2007)%2007;//总是忘记在最外面%2007

     }
     
     for(int j = i;j <= 100;j++)
     {
      p[i][j] = 0;
     }
  }
}

int main()
{
    check();
    int n,k;
     while(cin >> n && cin >> k)
    {
           cout << p[n][k] << endl;
    }
   // system("pause");
    return 0;
}                                 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值