度度熊最近对全排列特别感兴趣,对于1到n的一个排列,度度熊发现可以在中间根据大小关系插入合适的大于和小于符号(即 ‘>’ 和 ‘<’ )使其成为一个合法的不等式数列。但是现在度度熊手中只有k个小于符号即(‘<”)和n-k-1个大于符号(即’>’),度度熊想知道对于1至n任意的排列中有多少个排列可以使用这些符号使其为合法的不等式数列。
输入描述:
输入包括一行,包含两个整数n和k(k < n ≤ 1000)
输出描述:
输出满足条件的排列数,答案对2017取模。
输入: 5 2
输出: 66
一、暴力解不可行
n的范围为1000,全排列,在逐个去检查小于号有多少个,不可行
二、动态规划
dp(n,k)从dp(n-1, k)和dp(n-1,k-1)状态变化过来
具体递推公式 dp(i,j)表示0~i个数进行全排列,j表示j个小于符号。
dp(i,j) = dp(i-1,j-1)(i-j) +dp(i-1,j) (j+1)
i-j表示,在0到(i-1)中有j-1个小于符号,所以有i-j-1个大于符号(i-1个数说明有i-2个符号),将最后一个数i放在排列的开头也只增加了一个大于号
j+1同理,有j个小于符号,再加将i放在最右边
代码如下:
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
int n = scanner.nextInt();
int k = scanner.nextInt();
long[][] dp = new long[n+1][n+1];
if (n == 1){
System.out.println(1);
break;
}
dp[1][0] = 1;
dp[2][0] = 1;
dp[2][1] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 0; j < i; j++) {
if (j == 0){
dp[i][j] = 1;
}
else {
dp[i][j] = (dp[i-1][j-1]*(i-j) + dp[i-1][j]*(j+1))%2017;
}
}
}
System.out.println(dp[n][k]);
break;
}
}
}