补记:
AC之后点了一下页面下方的讨论版块,发现这个问题是非常著名的“错排公式”,下面就来学习一下。
比我的方法好,线性时间,cool!
/************************************
设f(n)表示n个人抽签无人中奖的情况总数,则题目要求的是f(n)/n!。
显然f(2)=1,f(3)=2。
我们来看看如何求f(4)。
f(4) = 4! - n(至少有一个人中奖)
= 4! - n(只有一人中奖,其他三人都没中) - n(只有两人中奖,其他两人没中) - n(有三个人中奖,意味着剩下的那个人也中奖了,即四个人都中奖)
= 4! - C(4, 1)*f(3) - C(4, 2)*f(2) - 1
= 24 - 8 - 6 - 1
= 9
一般地,我们有f(2)=1, f(n) = n! - SIGMA(i from 1 to n-2){C(n, i)*f(n-i)} - 1, n>=2。
************************************/
#include <iostream>
#include <iomanip>
using namespace std;
#define MAXN 21
long long NobodyWins[MAXN];
//阶乘
long long fact(int n)
{
if(n==0) return 1;
long long ans=1;
for (int i=1; i<=n; ++i)
{
ans*=i;
}
return ans;
}
//组合数
long long comb(int n, int i)
{
long long nume=1;
for (int j=0; j<i; ++j)
{
nume*=n;
--n;
}
long long deno=fact(i);
return nume/deno;
}
int main()
{
freopen("D:\\in.txt", "r", stdin);
freopen("D:\\out.txt", "w", stdout);
NobodyWins[2]=1;
for (int i=3; i<MAXN; ++i)
{
long long temp=0;
for (int j=1; j<=i-2; ++j)
{
temp += comb(i, j)*NobodyWins[i-j];
}
NobodyWins[i] = fact(i) - temp - 1;
}
int t, n;
double prob;
cin>>t;
while (t--)
{
cin>>n;
prob = (double)(NobodyWins[n])/((double)fact(n)) * 100;
cout<<fixed<<setprecision(2)<<prob<<"%"<<endl;
//cout<<NobodyWins[n]<<endl;
}
return 0;
}