Consider this sequence {1, 2, 3 ... N}, as an initial sequence of first N natural numbers. You can rearrange this sequence in many ways. There will be a total of N! arrangements. You have to calculate the number of arrangement of first N natural numbers, where in first M positions; exactly K numbers are in their initial position.
For Example, N = 5, M = 3, K = 2
You should count this arrangement {1, 4, 3, 2, 5}, here in first 3 positions 1 is in 1st position and 3 in 3rd position. So exactly 2 of its first 3 are in there initial position.
But you should not count {1, 2, 3, 4, 5}.
Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.
Each case contains three integers N (1 ≤ N ≤ 1000), M (M ≤ N), K (0 < K ≤ M).
Output
For each case, print the case number and the total number of possible arrangements modulo 1000000007.
Sample Input | Output for Sample Input |
2 5 3 2 10 6 3 | Case 1: 12 Case 2: 64320 |
分析:首先先确定固定位置的数是那几个暨C(M,K),然后在非[1,M]内还有N-M个数,在[1,M]内还有还有M-K个数,而且这M-K个数是应该处于错排的状态,我们需要做的是讨论外面的N-M个数中的参与错排的个数暨sum C[N-M,i]*D[M-K+i] (i=0...N-M] D 为错排数,注意本题中D[0]=1,也就是说当M=K且外面参与错排的个数为0时有且只有一种方法。
1,组合数表可以通过递推C(n,m)=C(n-1,m-1)+C(n-1,m)预处理打印,不要学我暴力直接用C(m,n)的公式,自己YY算法。。。,
for(int i=0;i<=1000;i++)
{
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
2,找的一个板子,使用于n,m不大,但mod很大的时候:
typedef long long LL;
const int P = 1000000007;
LL f[1000001], v[1000001];
LL rp(LL now, int k)
{
LL will = 1;
for (; k; k >>= 1, now *= now, now %= P)
{
if (k & 1) will *= now, will %= P;
}
return will;
}
LL C(int n, int m)
{
if(n < m) return 0;
return f[n] * rp(f[m], P - 2) % P * rp(f[n - m], P - 2) % P;
}
void init()
{
f[0] = 1; v[0] = 1;
for (int i = 1; i <= 1000000; i++) //1e6以内的组合数
{
f[i] = f[i - 1] * i % P;
}
}
int main()
{
init();
int n, m;
scanf("%d%d", &m, &n);
printf("%lld\n", C(m, n));
}
这道题的代码:
code:
#include<cstdio>
#include<cstring>
const long long mod=1000000007;
const int MAXN=1000+5;
long long D[MAXN];
typedef long long LL;
const long long P = 1000000007;
LL f[1000001], v[1000001];
LL rp(LL now, int k)
{
LL will = 1;
for (; k; k >>= 1, now *= now, now %= P)
{
if (k & 1) will *= now, will %= P;
}
return will;
}
LL C(int n, int m)
{
if(n < m) return 0;
return f[n] * rp(f[m], P - 2) % P * rp(f[n - m], P - 2) % P;
}
void init()
{
f[0] = 1; v[0] = 1;
for (int i = 1; i <= MAXN; i++) //1e6以内的组合数
{
f[i] = f[i - 1] * i % P;
}
D[1]=0,D[2]=D[0]=1;
for(int i=3;i<=MAXN;i++)
{
D[i]=1LL*(i-1)*(D[i-1]+D[i-2])%mod;
}
}
int main(void){
int T;scanf("%d",&T);
int CASE=0;
init();
while(T--){
int N,M,K;scanf("%d%d%d",&N,&M,&K);
LL Cmk=C(M,K);
LL res=0;
for(int i=0;i<=N-M;++i){//枚举M外的参加错排数的个数
res=(res+C(N-M,i)*D[M-K+i])%mod;
}
res=res*Cmk%mod;
printf("Case %d: %lld\n",++CASE,(res+mod)%mod);
}
}