题目描述
将
1
1
1 到
n
n
n 任意排列,然后在排列的每两个数之间根据他们的大小关系插入>
和 <
。问在所有排列中,有多少个排列恰好有
k
k
k 个 <
。答案对
2015
2015
2015 取模。
注: 1 ∼ n 1 \sim n 1∼n 的排列指的是 1 ∼ n 1 \sim n 1∼n 这 n n n 个数各出现且仅出现一次的数列。
输入格式
一行两个整数,表示 n n n 和 k k k。
输出格式
一个整数表示答案。
样例输入
5 2
样例输出
66
数据规模
对于
30
%
30\%
30% 的数据,
n
≤
10
n\leq 10
n≤10
对于
100
%
100\%
100% 的数据,
0
≤
k
<
n
≤
1000
0\leq k<n\leq 1000
0≤k<n≤1000
题解
我们换一个角度,在一个空的序列中从小到大插入 1 1 1到 n n n的每一个值,插入的位置任意。假设现在要插入的数为 c c c,要插入到 a , b a,b a,b之间,则
- 若 a < b a<b a<b,则插入后式子为 a < c > b a<c>b a<c>b, c c c的贡献为一个大于号
- 若 a > b a>b a>b,则插入后式子为 a < c > b a<c>b a<c>b, c c c的贡献为一个小于号
当然,也可以插在最左边和最右边, c c c的贡献分别是一个大于号和一个小于号。
设
f
i
,
j
f_{i,j}
fi,j表示当前有
i
i
i个大于或小于号(即当前已经放了
i
+
1
i+1
i+1个数字),
j
j
j表示这
i
i
i个不等号中有
j
j
j个小于号。由上文可推得转移式:
f
i
,
j
=
f
i
−
1
,
j
∗
(
j
+
1
)
+
f
i
−
1
,
j
−
1
∗
(
i
−
j
+
1
)
f_{i,j}=f_{i-1,j}*(j+1)+f_{i-1,j-1}*(i-j+1)
fi,j=fi−1,j∗(j+1)+fi−1,j−1∗(i−j+1)
然后答案就是 f n − 1 , k f_{n-1,k} fn−1,k。时间复杂度为 O ( n 2 ) O(n^2) O(n2)
code
#include<bits/stdc++.h>
using namespace std;
int t,n,k;
long long f[1005][1005];
long long mod=2015;
int main()
{
scanf("%d%d",&n,&k);
f[0][0]=1;
for(int i=1;i<n;i++){
for(int j=0;j<=i;j++){
f[i][j]=(f[i-1][j]*(j+1)%mod+f[i-1][j-1]*(i-j+1)%mod)%mod;
}
}
printf("%lld\n",f[n-1][k]);
return 0;
}