UVa 11481 Arrange the Numbers
题目大意:
可以将序列
1,2,3,...n
任意重排,但重排后的前
m
(
(注意是前m个位置恰好有k个不变,也就是说前m个位置的另外m-k个必须改变)
题目分析:
首先,前m个位置恰好有k个不变,则有 Ckm 个方案数,那么总共的方案数为 Ckm∗An−kn−k .
但是,方案数中还存在前m个元素中另外m-k个元素仍在原位置的情况.
利用容斥原理:
减去1个元素在原位置的方案数,加上2个元素在原位置的方案数…
所以总方案数为 Ckm∗(An−kn−k−∑n−ki=1(−1)i∗Cim−k∗An−k−in−k−i) .
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000;
const int MOD=1000000007;
int C[maxn+1][maxn+1],A[maxn+1];//C[i][j]表示i个元素选j个元素的种类数,A[i]表示i个元素选i个元素的排列种类数
void init(int n)
{
C[0][0]=1;
for(int i=1;i<=n;i++) {
C[i][0]=1;
for(int j=1;j<=n;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
A[0]=1;
for(int i=1;i<=n;i++) A[i]=(1ll*A[i-1]*i)%MOD;
}
int main()
{
init(maxn);
int T,N,M,K,kase=0;
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&N,&M,&K);
int B=A[N-K];
for(int i=1;i<=N-K;i++) B=(0ll+B+((i&1)?-1:1)*(1ll*C[M-K][i]*A[N-K-i]%MOD))%MOD;
B=(B%MOD+MOD)%MOD;//注意加法和乘法的溢出
printf("Case %d: %lld\n",++kase,1ll*C[M][K]*B%MOD);
}
return 0;
}