LightOJ - 1095 - Arrange the Numbers(组合数+错排公式)

1095 - Arrange the Numbers

    PDF (English) Statistics Forum
Time Limit: 2 second(s) Memory Limit: 32 MB

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

题意:给你三个数n,m,k(k<=m<=n<=1000),求1~n的全排列中有多少排列的前m个数中恰有k个数的值和其所在位置相等。

思路:

首先从前m个中选k个保持位置不变,剩下的m-k个数必须错排,但后面的的n-m个数可错排也可不错排。因此我们枚举后面的n-m个数有多少个数错排,答案就是

C_{m}^{k}*\sum_{i=0}^{n-m}\left ( d[n-k-i]*C_{n-m}^{i} \right )

代码:

#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
const int maxn=1010;
const ll mo=1e9+7;
const double eps=1e-9;
ll n,m,k;
ll d[maxn],c[maxn][maxn];
void init()
{
    d[0]=d[2]=1;d[1]=0;
    for(ll i=3;i<maxn;i++)
    d[i]=(i-1)*(d[i-1]+d[i-2])%mo;
    c[0][0]=1;
    for(int i=1;i<maxn;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i;j++)
        c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
    }
}
int main()
{
    init();
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        ll ans=0;
        for(int i=0;i<=n-m;i++)
        ans=(ans+d[n-k-i]*c[n-m][i]%mo)%mo;
        ans=ans*c[m][k]%mo;
        printf("Case %d: %lld\n",cas++,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LSD20164388/article/details/89071743
今日推荐