湘潭大學程序設計實踐 1194

xtuoj 1194

Recipient

 

Description

題目描述

快遞小哥每天都辛苦的送快遞,今天他需要送N份快遞給N個收件人,第i份快遞需要送給第i個收件人。 請問其中發生恰好K個送錯了的情況數是多少?

輸入

存在多樣例。 每行輸入兩個整數N和K,1≤N≤1000,0≤K≤N。 如果兩個都爲0,則表示輸入結束,這個樣例不需要處理。

輸出

每行輸出一個樣例的結果,因爲數值會比較大,所有結果需要對109+7取模。

樣例輸入

1 1
2 1
3 2
1000 1000
0 0

樣例輸出

0
0
3
37043040
這個題目其實就是三個點要注意:
1.錯排遞推公式:D[i] = (i-1)*(D[i-1] + D[i-2]) (i > 2) D[1] = 0, D[2] = 1;(公式詳解找維基百科:錯排)
2.排列組合公式(楊輝三角):	C[i][j] = C[i-1][j] + C[i-1][j-1] (0 < i < 1000, j < i)
				C[i][0] = C[i][i] = 1 (i < 1001) 
3.就是就是當k爲0的時候結果爲1(我就是卡在這,開始怎麼都沒有想到0個沒錯其實就是全部送對,而全部送對就只有1種情況嘛!)

#include<cstdio>
using namespace std;
const int N = 1001;
const int mod = 1000000007;
#define ll long long
ll d[N], c[N][N];
int main()
{
    //求錯排
    d[2] = 1;
    for(int i = 3; i < N; i ++)
        d[i] = (i - 1) * (d[i-1] + d[i-2]) % mod;
    //求組合數
    for(int i = 1; i < N; i ++)
        c[i][0] = c[i][i] = 1;
    for(int i = 2; i < N; i ++)
        for(int j = 1; j < i; j ++)
            c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
    int n, k;
    while(~scanf("%d%d", &n, &k), n + k)
        if(!k)
            printf("1\n"); //k爲0時輸出結果爲1
        else
            printf("%I64d\n", d[k] * c[n][k] % mod);
    return 0;
}


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