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. 后记

哇,这篇写了超长时间,从开始写这个题,然后寻找其他解法,再然后写各种代码,简直是我写过最长时间的一篇了。

posted @ 2020-12-14 14:46  面包络合物  阅读(91)  评论(0编辑  收藏  举报