国王的秘书
题目描述
国王需要向他所有的传道人分发指示。由于每位部长都需要一套独特的指示,他会为每位部长写一封个性化的信件,并将其交给他的秘书递送。
不幸的是,国王的秘书是一个非常粗心的家伙。他忘记了每位部长都有自己的个性化信件,而是随机向每位部长发信。在他意识到自己的错误后,他开始逐一召唤传道人,并询问他们是否收到了正确的信件。到目前为止,他已经召集了N名部长中的K位,并且令他感到恐惧的是,K位部长都没有收到正确的信件。
国王对他的秘书感到愤怒,但他决定给他最后一次机会来挽救他的工作。他问秘书以下问题。他有多少种方式分发这些信件,以便能够出现现状?换句话说,这些信件的分配方式有多少,以至于到目前为止所调用的每个K部长都写了一封错误的信?如果至少有一位部长获得不同的信件,则认为两种方式不同。如果秘书能够正确回答这个问题,他可以继续工作。你的工作是通过为他计算正确答案来帮助秘书。由于答案可能非常大,因此返回模数1,000,000,007。
输入格式
多组测试数据。
第一行,一个整数G,表示有G组测试数据。 1 <= G <= 10
每组测试数据格式:
一行,两个整数,N和K。1 <= N <= 1000, 1<=K<=12。1 <= k <=N。
输出格式
共G行,每行一个整数。
输入样例
10
2 1
3 1
9 9
5 1
6 2
3 3
7 4
9 1
4 2
3 2
输出样例
1
4
133496
96
504
2
2790
322560
14
3
解题思路
本题大意:K位部长都没有收到正确的信的情况有多少种?
根据题意,我们只需计算前K个部长没有收到正确信件的情况就行了,其他部长可以随意排列。
但是直接从正面思考,这个想法是错误的,而且我们发现这样算特别难算。
从反面思考问题,答案=所有情况-至少有一个部长拿对信封的情况。
我们可以在容斥原理这个角度入手,那么我们可以想到:在这K个人中至少1人拿对信件的情况是 ( n − 1 ) ! × C K 1 (n-1)!\times C_K^1 (n−1)!×CK1种;
但是在这些情况中会出现2个人拿对信件的情况,所以要减去 ( n − 2 ) ! × C K 2 (n-2)!\times C_K^2 (n−2)!×CK2;
紧接着我们又发现减去的时候,减多了一些情况,这些情况是3个人拿对信件的情况,所以加上 ( n − 3 ) ! × C K 3 (n-3)!\times C_K^3 (n−3)!×CK3;
⋯ ⋯ \cdots\space\cdots ⋯ ⋯
根据上面的思路,我们可以直接推出本题的答案: ( n − 1 ) ! × C K 1 − ( n − 2 ) ! × C K 2 + ( n − 3 ) ! × C K 3 ⋯ (n-1)!\times C_K^1-(n-2)!\times C_K^2+(n-3)!\times C_K^3\cdots (n−1)!×CK1−(n−2)!×CK2+(n−3)!×CK3⋯当 i i i是奇数时加上结果,当 i i i是偶数时减去结果
代码
/*
m
C(n,m)=C
n
从正面想得到一个错误的思路:n!-(n-1)!*k+(n-2)!*(k-1)...
反过来想,答案=所有情况-K个人中至少有1个拿到对的信件的情况
K个人中至少有1个拿到对的信件的情况
=(n-1)!*C(k,1)-(n-2)!*C(k,2)+(n-3)!*C(k,3)...
C(k,i):在K个人中有任意i个人拿对
(n-i)!:剩下的n-i个人拿到信件的所有情况
*/
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
long long G,C[30][30];
long long a[1005];
long long ans;
int N,K;
int main()
{
a[0]=1;a[1]=1;
for(int i=2;i<=1002;i++)
a[i]=a[i-1]*i%1000000007;//求阶乘
for(int i=0;i<=25;i++)
{
C[i][i]=1;
C[i][0]=1;
}
for(int i=1;i<=25;i++)
for(int j=1;j<i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];//求组合数
freopen("2786.in","r",stdin);
freopen("2786.out","w",stdout);
cin>>G;
for(int gr=1;gr<=G;gr++)
{
cin>>N>>K;
ans=a[N];
for(int i=1;i<=K;i++)
{
if(i%2==0)
{
ans+=C[K][i]*a[N-i]%1000000007;
ans%=1000000007;
}
else
{
ans-=C[K][i]*a[N-i]%1000000007;
if(ans<0) ans+=1000000007;
else
ans%=1000000007;
}
}
cout<<ans<<endl;
}
return 0;
}