湘潭大学程序设计实践 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
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;
}


你可能感兴趣的:(湘潭大学程序设计实践 1194)