链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2476
题解
用
f
i
j
f_{ij}
fij表示
i
i
i的全排列中,前
j
j
j个数字不能在原位置的方案数
f
i
,
0
=
i
!
f_{i,0}=i!
fi,0=i!
生成一个排列的过程,可以看作一开始有
i
i
i个空位,我把
i
i
i个数依次放到一个空位上的过程
当
j
>
0
j>0
j>0时
假设我先放
1
1
1,
1
1
1如果放在前
j
j
j个位置上(除了第1个位置),剩下的问题就成了
i
−
1
i-1
i−1个数,有
j
−
2
j-2
j−2个数不能放在某一个特定位置上
1
1
1如果放在后面
i
−
j
i-j
i−j个位置上,剩下的问题就成了
i
−
1
i-1
i−1个数,有
j
−
1
j-1
j−1个数不能放在某一个特定位置上
因此
f
i
j
=
(
j
−
1
)
f
i
−
1
,
j
−
2
+
(
i
−
j
)
f
i
−
1
,
j
−
1
f_{ij}=(j-1)f_{i-1,j-2}+(i-j)f_{i-1,j-1}
fij=(j−1)fi−1,j−2+(i−j)fi−1,j−1
注意
j
=
1
j=1
j=1时
f
i
j
=
(
i
−
j
)
f
i
−
1
,
j
−
1
f_{ij}=(i-j)f_{i-1,j-1}
fij=(i−j)fi−1,j−1
代码
//递推
#include <bits/stdc++.h>
#define maxn 1010
#define mod 1000000007ll
#define ll long long
using namespace std;
ll f[maxn][maxn], C[maxn][maxn];
ll read(ll x=0)
{
ll c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
return f*x;
}
void preprocess()
{
ll i, j;
for(i=0;i<maxn;i++)C[i][0]=1;
for(i=1;i<maxn;i++)for(j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
f[0][0]=1;
f[1][0]=1, f[1][1]=0;
for(i=2;i<maxn;i++)
{
for(f[i][0]=1,j=1;j<=i;j++)f[i][0]=f[i][0]*j%mod;
f[i][1]=(i-1)*f[i-1][0]%mod;
for(j=2;j<=i;j++)f[i][j]=((j-1)*f[i-1][j-2]+(i-j)*f[i-1][j-1])%mod;
}
}
int main()
{
freopen("in.txt","r",stdin);
ll T=read(), kase, N, M, K;
preprocess();
for(kase=1;kase<=T;kase++)
{
N=read(), M=read(), K=read();
printf("Case %lld: %lld\n",kase,C[M][K]*f[N-K][M-K]%mod);
// printf("%lld*%lld\n",C[M][K],f[N-K][M-K]);
}
return 0;
}