题目描述

过年期间,老家举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做“考新郎”,具体的操作是这样的:

1. 首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;
2. 然后,让各位新郎寻找自己的新娘。每人只准找一个,并且不允许多人找一个;
3. 最后,揭开盖头,如果找错了对象就要当众跪搓衣板...

假设一共有n对新婚夫妇,其中有m个新郎找错了新娘,求发生这种情况一共有多少种可能。

输入描述:

输入包含多组数据。每组数据包含两个正整数n和m(2≤m≤n≤20)


输出描述:

对应每一组数据,输出一个正整数,表示n对新人中有m个新郎找错新娘的种数。

输入例子:

2 2
3 2

输出例子:

1
3
 意思就是说,先从n里选出m个,就是C(n,m),然后把这m个排序,前提是不能有任何一个是对应正确位置,也就是说不能有新郎选对了新娘,所有的应该排在错误的位置,这里就想到了容斥定理,总的排列是m!,然后得减去那些存在新郎选对新娘的,如果1个新郎一定选对了,其他的还有(m - 1)!种排法,且这些排法都不满足,而且这些排法中也存在其他m-1个新郎选对的情况,总的应该减去C(m,1)个(m - 1)!,但是这C(m,1)个当中仍然有重复的,还得加,任意两个都会有重复,重复的是(m - 2)!,所以加上C(m,2)个(m - 2)!,然后又是减,加。。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;
int n,m;
long long fact[21];
long long C(int a,int b) {
    long long aa = 1,bb = 1;
    for(int i = 0;i < b;i ++) {
        aa *= a - i;
        bb *= (i + 1);
    }
    return aa / bb;
}
int main() {
    fact[0] = 1;
    for(int i = 1;i <= 20;i ++) {
        fact[i] = fact[i - 1] * i;
    }
    while(~scanf("%d%d",&n,&m)) {
        long long e = fact[m],flag = -1;
        for(int i = 1;i <= m;i ++,flag *= -1) {
            e += fact[m - i] * C(m,i) * flag;
        }
        printf("%lld\n",C(n,m) * e);
    }
}