hdoj 3664 Permutation Counting 【递推 有点类似杨辉三角】

Permutation Counting

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


Problem Description
Given a permutation a1, a2, … aN of {1, 2, …, N}, we define its E-value as the amount of elements where ai > i. For example, the E-value of permutation {1, 3, 2, 4} is 1, while the E-value of {4, 3, 2, 1} is 2. You are requested to find how many permutations of {1, 2, …, N} whose E-value is exactly k.
 

Input
There are several test cases, and one line for each case, which contains two integers, N and k. (1 <= N <= 1000, 0 <= k <= N).
 

Output
Output one line for each case. For the answer may be quite huge, you need to output the answer module 1,000,000,007.
 

Sample Input
   
   
   
   
3 0 3 1
 

Sample Output
   
   
   
   
1 4
Hint
There is only one permutation with E-value 0: {1,2,3}, and there are four permutations with E-value 1: {1,3,2}, {2,1,3}, {3,1,2}, {3,2,1}
 


从组合角度:

用dp[ n ][ k ]表示 n个数组成的数列 中价值为k的序列数目。

对于数字n分三种情况:

1, 数字n在最后一位(不用考虑它),那么则有序列数目dp[ n-1 ][ k ];

2, 数字n不在最后一位  且当前序列已有价值k ,只需将数字n和序列中k个数(指a[k] > k 的数字)之一交换位置,那么有序列数目dp[n-1][k] * k;

3, 数字n不在最后一位 且当前序列已有价值k-1,我们只需将数字n和序列中n-k个数 (指a[k] <= k 的数字)之一交换位置,那么有序列数目dp[n-1][k-1] * (n-k);

(不要犯晕,这里我们讨论的是数字n的位置,不讨论其他数字的情况,若讨论的话。。。)

(不要问我为什么不讨论 当前序列已有价值k-2或者k-3的情况。。。)

 

最后得出dp[n][k] = dp[n-1][k] + dp[n-1][k] *k + dp[n-1][k-1] * (n-k)。

便于理解给出一个表格:

行\列

0

1

2

3

4

5

6

1

1

0

 -

-

-

-

-

2

1

1

0

-

-

-

-

3

1

4

1

0

-

-

-

4

1

11

11

1

0

-

-

5

1

26

66

26

1

0

-

6

1

57

302

302

57

1

0

 

 

 

为了方便输出,可以先打表:

 

 

#include <cstdio>
#include <cstring>
#define LL long long
#define MAX 1000+1
#define MOD 1000000007
using namespace std;
LL dp[MAX][MAX];
void getdp()
{
	dp[1][0] = 1;dp[1][1] = 0;
	for(int i = 2; i < MAX; i++)
	{
		dp[i][0] = 1;
		for(int j = 0; j <= i; j++)
		{
			dp[i][j] = (dp[i-1][j]%MOD + (dp[i-1][j]*j)%MOD + (dp[i-1][j-1]*(i-j))%MOD)%MOD;
		}
	}
}
int main()
{
	int n, k;
	getdp();
	while(~scanf("%d%d", &n, &k))
	{
		printf("%lld\n", dp[n][k]);
	}
	return 0;
} 


 

你可能感兴趣的:(hdoj 3664 Permutation Counting 【递推 有点类似杨辉三角】)