欢迎访问https://blog.csdn.net/lxt_Lucia~~
宇宙第一小仙女\(^o^)/~~萌量爆表求带飞=≡Σ((( つ^o^)つ~ dalao们点个关注呗~~
----------------------------------------我只是一条可爱哒分界线-------------------------------------------
一、问题:
Description
The first question on the Data Structures and Algorithms final exam has a list of N terms and a second list of N definitions. Students are to match each term with the correct definition.
Unfortunately, Joe, who wrote a Visual BASIC program in high school and assumed he knew all there was to know about Computer Science, did not bother to come to class or read the textbook. He has to guess randomly what the matches are. Let S(N, k) be the number of ways Joe can answer the question and get at least the first k matches wrong.
For this problem, you will write a program to compute S(N, k).
Input
The first line of input contains a single integer P, (1 ≤ P ≤ 1000), which is the number of data sets that follow. Each data set should be processed identically and independently.
Each data set consists of a single line of input containing three space separated decimal integers. The first integer is the data set number. The second integer is the number, N (1 ≤ N ≤ 17), of terms to be matched in the question. The third integer is the number, k (0 ≤ k ≤ N), of initial matches to be incorrect.
Output
For each data set there is a single line of output. It contains the data set number followed by a single space which is then followed by the value of S(N, k).
Sample Input
4
1 4 1
2 7 3
3 10 5
4 17 17
Sample Output
1 18
2 3216
3 2170680
4 130850092279664
二、题意:
用 n 条释义匹配 n 个术语,求至少前 k 个匹配错误的情况总数 S(n,k)。
三、思路:
1)首先,至少前k个匹配错,做起来很麻烦,我们找它的对立事件:至多前k个对。
2)假设n=7, k=3:
当计算前三个只有一个匹配正确时,我们得到的情况数为 C(3,1)*A(6,6) ,即从前3个中选一个认为对,其他6个乱排。我们发现,这重复计算了有2个匹配正确和有3个匹配正确的情况,于是我们减去有2个匹配正确的情况数C(3,2)*A(5,5),我们又发现这样多减掉了三个匹配正确的情况,于是再加回来C(3,3)*A(4,4)。
最终的到情况总数为 C(3,1)*A(6,6) - C(3,2)*A(5,5) + C(3,3)*A(4,4)。
以此类推,我们就得出了计算方式:取奇数时加,偶数时减,最终求出至多前k个对的情况数。
3)所求 = 所有情况数 - 至多前k个对的情况数 ,即 A(n,n) - sum。
4)下面的代码中,我用 a [ i ] 表示 i 的阶乘,先计算出了a 数组,因为1 ≤ N ≤ 17,用的时候直接取,不必重复计算,省时省力。
a [ k ] / ( a [ k - i ] * a [ i ] ) 就是C(k,i),排列组合公式。emmm... 记得开long long...
四、代码:
#include <cstdio>
#define read(x) scanf("%d",&x)
#define fori(a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
LL a[20];
void JieCheng()
{
a[0]=a[1]=1;
fori(2,19)
a[i]=a[i-1]*i;
}
int main()
{
int T,num,n,k;
read(T);
JieCheng();
while(T--)
{
LL sum=0;
scanf("%d %d %d",&num,&n,&k);
fori(1,k)
{
if(i&1)
sum+=(a[k]/(a[k-i]*a[i]))*a[n-i];
else
sum-=(a[k]/(a[k-i]*a[i]))*a[n-i];
}
printf("%d %lld\n",num,a[n]-sum);
}
return 0;
}