湘潭大学oj1194

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种情况嘛!)

  1. #include<cstdio>  
  2. using namespace std;  
  3. const int N = 1001;  
  4. const int mod = 1000000007;  
  5. #define ll long long  
  6. ll d[N], c[N][N];  
  7. int main()  
  8. {  
  9.     //求错排  
  10.     d[2] = 1;  
  11.     for(int i = 3; i < N; i ++)  
  12.         d[i] = (i - 1) * (d[i-1] + d[i-2]) % mod;  
  13.     //求组合数  
  14.     for(int i = 1; i < N; i ++)  
  15.         c[i][0] = c[i][i] = 1;  
  16.     for(int i = 2; i < N; i ++)  
  17.         for(int j = 1; j < i; j ++)  
  18.             c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;  
  19.     int n, k;  
  20.     while(~scanf("%d%d", &n, &k), n + k)  
  21.         if(!k)  
  22.             printf("1\n"); //k为0时输出结果为1  
  23.         else  
  24.             printf("%I64d\n", d[k] * c[n][k] % mod);  
  25.     return 0; 
  26. }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值