lightoj1095 Arrange the Numbers 組合數學

題目:

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);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章