文章目录

1 题目

年会抽奖
时间限制 1000 ms 内存限制 32768 KB 代码长度限制 100 KB 判断程序 Standard (来自 小小)
题目描述
今年公司年会的奖品特别给力,但获奖的规矩却很奇葩:

  1. 首先,所有人员都将一张写有自己名字的字条放入抽奖箱中;
  2. 待所有字条加入完毕,每人从箱中取一个字条;
  3. 如果抽到的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
    现在告诉你参加晚会的人数,请你计算有多少概率会出现无人获奖?

输入描述:
输入包含多组数据,每组数据包含一个正整数n(2≤n≤20)。

输出描述:
对应每一组数据,以“xx.xx%”的格式输出发生无人获奖的概率。

输入例子:
2

输出例子:
50.00%

2 解析

2.1 题意

见题目

2.2 思路

错排问题,推导如下,
若前n-1个数已经满足错排,现考虑第n个数:
(1)第n个数可以和前n-1个中任意一个数互换,结果仍然是错排,所以有(n-1)*D(n-1)种;
(2)第n个数可以放到前n-1任意一个位置,但是原来位置的数不能放到最后,
则其只可以能放在其他n-2个位置,并且保证这n-2的位置是错排,所以有(n-1)*D(n-2)

综上,一共有 D(n) =(n-1)*(D(n-1)+D(n-2))

例如:
经典的装错信封问题
用A、B、C……表示写着n位友人名字的信封,a、b、c……表示n份相应的写好的信纸。把错装的总数为记作D(n)。假设把a错装进B里了,包含着这个错误的一切错装法分两类:
(1)b装入A里,这时每种错装的其余部分都与A、B、a、b无关,应有D(n-2)种错装法。
(2)b装入A、B之外的一个信封,这时的装信工作实际是把(除a之外的)n-1份信纸b、c……装入(除B以外的)n-1个信封A、C……,显然这时装错的方法有D(n-1)种。
总之在a装入B的错误之下,共有错装法D(n-2)+D(n-1)种。
a装入C,装入D……的n-2种错误之下,同样都有D(n-1)+D(n-2)种错装法,因此D(n)=(n-1)[D(n-1)+D(n-2)]

因此得错排公式:D(n)=(n-1)[D(n-1)+D(n-2)],D[0] = 1,D[1] = 0,D[2] = 1。

3 参考代码

#include 
#include

typedef long long ll;

const int MAXN = 21;
ll fac[MAXN] = {1, 1, 2};
ll f[MAXN] ={1, 0, 1};

int main()
{
int n;
for (int i = 3; i < MAXN; ++i) {
fac[i] = fac[i - 1]*i;
f[i] = (i - 1) * (f[i-1] + f[i -2]);
}

while (~scanf("%d",&n))
{
double ans = (1.0*f[n]) / fac[n] * 100;
printf("%2.2f%%\n", ans);
}
return 0;
}