题目链接
本题是2010年ICPC 亚洲区域赛 哈尔滨赛区的题目
题意
给定 1~n 的排列{a1, a2, …, an},满足ai>i 的下标i 的个数称为此排列的E 值。例如{1,3,2,4}的E 值为1,{4, 3, 2, 1}的E 值为2。给定整数n 和k(1≤n≤1 000,0≤k≤n),求E 值恰好为k 的排列个数。
分析
递推求解,用f[n][k]表示递推状态,对问题做适当转化可构建出递推式。
若排列的1号位放的数正好是1,则转化成了f[n-1][k]。接下来考虑1也参与交换对结果的变化:若1和某个ai>i的元素交换,则转化成了新的排列但计数结果仍然f[n-1][k],当ai>i的元素有k个时有k种交换选择;若1和某个ai≤i的元素交换,则新排列的1号位新增一个ai>i的元素,当ai>i的元素有k-1个时有n-k种交换选择。
至此,可以得出递推式:f[n][k] = f[n-1][k] + k*f[n-1][k] + (n-k)*f[n-1][k-1]
= (k+1)*f[n-1][k] + (n-k)*f[n-1][k-1]
AC代码
#include <iostream>
using namespace std;
#define M 1000000007
#define N 10002
int f[N][N>>1], n, k;
int solve() {
return k >= n ? 0 : ((k<<1) < n ? f[n][k] : f[n][n-1-k]);
}
int main() {
for (long long n=1; n<N; ++n) {
f[n][0] = 1;
for (long long k=1, m=(n-1)>>1; k<=m; ++k)
f[n][k] = ((f[n-1][(k<<1) < n-1 ? k : k-1])*(k+1) + f[n-1][k-1]*(n-k)) % M;
}
while (cin >> n >> k) cout << solve() << endl;
return 0;
}