HDU2048神、上帝以及老天爷
1. 题面
2. 解法
- 错排公式
将\(N\)个编号元素放在\(N\)个编号位置,求元素编号和位置编号不相同的方案数。这样的问题我们称为错排问题
递推公式$$D[n] = (n-1)*[D[n-1]+D[n-2]]$$
其中\(D[n]\)表示方案数
下面给出证明:
第一步,把第\(n\)个元素放在一个位置上,有\(n-1\)种放法
第二步,放第\(k\)个元素时,有两种情况。(1)放在第n号位置时,剩下的\(n-2\)个元素有\(D[n-2]\)种方法。(2)不放在n号位置时,这\(n-1\)个元素有\(n-1\)种放置方法。
由加法原理和乘法原理得:
\[D[n] = (n-1)*[D[n-1]+D[n-2]]
\]
接下来的事情就非常简单了,只需要递归计算\(D[n]\),然后除\(n!\)即可。
#include<bits/stdc++.h>
using namespace std;
unsigned long long fact[21];
unsigned long long dfs(int n)
{
if(n == 1) return 0;
if(n == 2) return 1;
return (n - 1) *(dfs(n - 2) + dfs(n - 1));
}
int main()
{
int cnt,t;
fact[1] = 1;
for(int i = 2;i <= 20;i ++ )
{
fact[i] = fact[i - 1] * i;
}
cin >> t;
for(int i = 1;i <= t;i ++ )
{
cin >> cnt;
cout << fixed << setprecision(2) << dfs(cnt) * 1.0 / fact[cnt] * 100 << "%" << endl;
}
return 0;
}
- 容斥原理
正整数\(1, 2, 3,\cdots, n\)的全排列有\(n!\)种,其中第\(k\)位是\(k\)的排列有\((n-1)!\)种;当\(k\)分别取\(1, 2, 3,\cdots, n\)时,共有\(n*(n-1)!\)种排列是至少放对了一个的,由于所求的是错排的种数,所以应当减去这些排列;但是此时把同时有两个数不错排的排列多排除了一次,应补上;在补上时,把同时有三个数不错排的排列多补上了一次,应排除;\(\cdots\cdots\);继续这一过程,得到错排的排列种数为
\[D(n) = n! - \frac{n!}{1!} + \frac{n!}{2!} - \frac{n!}{3!} + \cdots + \frac{{-1}^{n}*n!}{n!} = \sum_{k=2}^{n}\frac{{-1}^{k} * n!}{k!}
\]
#include<bits/stdc++.h>
using namespace std;
int n;
long long b[21];
int main()
{
b[1] = 1;
for(int i = 2;i <= 20;i ++ )
{
b[i] = b[i - 1] * i;
}
int t;
cin >> t;
for(int i = 1;i <= t;i ++ )
{
long long sum = 0;
cin >> n;
for(int k = 2;k <= n;k ++ )
{
sum += (pow(-1,k) * b[n]) / b[k];
}
cout << fixed << setprecision(2) << ((sum * 1.0) / b[n]) * 100 << "%" << endl;
}
return 0;
}
- 错排公式
这个东西是
\[D(n)= [\frac{n!}{e}+0.5]
\]
具体怎么证明我也不太清楚,高数还没学到,贴一下百度百科上的证明好力(
证明:
由于$$\frac{1}{e} = e^{-1} = \frac{1}{0!} - \frac{1}{1!} + \frac{1}{2!} - \frac{1}{3!} - \cdots + \frac{{-1}^{n}}{n!} + Rn(-1)$$,
其中\(Rn(-1)\)是余项,等于\(\frac{{-1}^{n+1} * e^u}{(n+1)!}\),且\(u \in (-1, 0)\).
所以,$$D(n) = n! * {e}^{-1} - \frac{{-1}^{n+1} * e^u}{(n+1)},u∈(-1, 0)$$
而$$|n! Rn| = |\frac{{-1}^{n+1} * {e}^{u}}{n+1}| = \frac{{e}^{u}}{n+1} \in (\frac{1}{[e(n+1)]}, \frac{1}{(n+1)})$$可知即使在\(n=1\)时,该余项(的绝对值)也小于\(\frac{1}{2}\)。
因此,无论\(n! Rn\)是正是负,\(\frac{n!}{e} + \frac{1}{2}\)的整数部分都一定与M(n)相同。
#include<bits/stdc++.h>
using namespace std;
#define e 2.718281828459
int main()
{
int n,m,t;
double a[21] = {1,1,2,6};
long long b[21] = {0,0,1,2};
for(int i = 4;i <= 20;i ++ )
{
a[i] = a[i - 1] * i;
b[i] = (a[i]/e + 0.5);
}
cin >> t;
for(int i = 1;i <= t;i ++ )
{
cin >> n;
printf("%.2lf%%\n",b[n]/a[n]*100);
}
return 0;
}
4. 后记
哇,这篇写了超长时间,从开始写这个题,然后寻找其他解法,再然后写各种代码,简直是我写过最长时间的一篇了。
流萤断续光,一明一灭一尺间