题目描述
将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2015取模。
注:1~n的排列指的是1~n这n个数各出现且仅出现一次的数列。
输入输出格式
输入格式:
第一行2个整数n,k。
输出格式:
一个整数表示答案。
输入输出样例
说明
对于30%的数据:n <= 10
对于100%的数据:k < n <= 1000
//dp[i][j]表示前i个数插入了j个<号的方案数。 //不考虑怎么插入'>'、'<'号,因为符号是根据数字序列确定的, //所以我们按顺序插入a->f,符号也就跟着确定了 //考虑一下这样一个序列: // a<b<d>c<e // 如果在a<b之间插入f,则变成了a<b>f,<号个数不变 // 如果在a之前插入f,则f>a,<号个数也不变 // 即在<号和序列前插入,<号的个数不会改变 //所以dp[i][j]可以增加dp[i-1][j]*( j + 1 )%mod种 // <号个数 序列前端 // 如果在d>c之间插入f,则变成了d<f>c,增加了一个<号 // 如果在e后面插入f,则e<f,增加了一个<号 // 即在>号和序列末插入,<号的个数会增加1 //所以dp[i][j]可以增加dp[i-1][j-1]*( (i-1) - (j-1) -1 + 1 -> i-j )%mod个 // 数字个数 <号个数 符号个数为数字个数-1 序列末尾 大于号个数+序列末尾 //即dp[i][j]=(dp[i-1][j-1]*(i-j)%mod+dp[i-1][j]*(j+1)%mod)%mod;
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=1e3+5; const int mod=2015; int n,k; int dp[N][N]; int main() { scanf("%d%d",&n,&k); dp[1][0]=1; for(int i=2;i<=n;++i) { dp[i][0]=1; //前i个数0个<号的情况只有1种,即单调上升。 for(int j=1;j<=k;++j) { dp[i][j]=(dp[i-1][j-1]*(i-j)%mod+dp[i-1][j]*(j+1)%mod)%mod; } } printf("%d",dp[n][k]); return 0; }