acm中的“组合数”和“错排”

Recipient

[ Submit Code ] [ Top 20 Runs ]
Acceteped : 66 Submit : 227
Time Limit : 1000 MS Memory Limit : 65536 KB
 

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



解释:
组合数和错排这里的解法都是用到的递推
组合数:递推公式是C(n,m)=C(n-1,m-1)+C(n,m-1);因为对于m个物体中的一个物体,要么被选,要么不被选,两种可能,所以如果被选了,就只需要从剩下的m-1个物体中选n-1个即C(n-1,m-1),
如果没有被选,就需要从剩下的m-1个物体中选n个即C(n,m-1),然后相加,即C(n,m)=C(n-1,m-1)+C(n,m-1)。
错排公式:递推公式为f(n)=(n-1)*(f(n-1)+f(n-2));因为对于n个物体错排,如果第一个物体错排的是第k个物体(n-1)种选择,那么分析第k个物体,如果第k个物体的位置错排的是第1个物体那么剩下的n-2个物体再进行错排就可以了即f(n-2)
如果第k个物体的位置错排的不是第1个物体而是w那么就相当于把第k个物体扔了直接再第一个物体下面排w即f(n-1)然后相加。即f(n)=(n-1)*(f(n-1)+f(n-2))。

代码如下
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod =1000000007;
long long c[1005][1005],f[1005];
void init1()
{
    for(int i=0;i<1005;i++){
        c[i][i]=c[0][i]=1;
    }
    for(int i=1;i<1005;i++){
        for(int j=i+1;j<1005;j++){
            c[i][j]=(c[i-1][j-1]+c[i][j-1])%mod;
        }
    }
}
void init2(){
    f[0]=1;
    f[1]=0;
    f[2]=1;
    for(int i=3;i<1005;i++){
        f[i]=((i-1)*(f[i-2]+f[i-1]))%mod;
    }
}
int main(){
    int n,k;
    init1();
    init2();
    while(~scanf("%d%d",&n,&k),n+k){;
        printf("%I64d\n",(c[n-k][n]*f[k])%mod);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值