Permutation
题目链接:http://soj.me/show_problem.php?pid=1002&cid=1035
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 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.
The nonnegative integer result mod 2007 on a line.
5 2
66
分析:p[i][j]:表示i个数字,k个小于号的方案数。
假如已经知道了1-4的排列,把5加上去,可能的情况是:
(1) 5在最前面,这样会在原来的状态下多加了一个 >; 即:5>xxxxx
(2) 5在最后面,这样就多加了一个<;即:xxxxx<5;
(3) 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;
}