题解 P1595 【信封问题】

YoungNeal

2018-03-18 17:30:21

Solution

题解在博客[食用](http://www.cnblogs.com/YoungNeal/p/8485399.html)效果更佳哦~ 我们先来科普一下错排问题,oier们以后也会用到/ 错排问题指考虑一个有 $n$ 个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 $n$ 个元素的错排数记为 $D(n)$ 。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。 ---《百度百科》 看上去这就是一个递推问题,那么递推式是如何推出来呢? 当 $n$ 个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用 $D(n)$ 表示,那么 $D(n-1)$ 就表示 $n-1$ 个编号元素放在 $n-1$ 个编号位置,各不对应的方法数,其它类推. 第一步,把第 $n$ 个元素放在一个位置,比如位置 $k$ ,一共有 $n-1$ 种方法; 第二步,放编号为 $k$ 的元素,这时有两种情况:⑴把它放到位置 $n$ ,那么,对于剩下的 $n-1$ 个元素,由于第 $k$ 个元素放到了位置 $n$ ,剩下 $n-2$ 个元素就有 $D(n-2)$ 种方法;⑵第 $k$ 个元素不把它放到位置 $n$ ,这时,对于这 $n-1$ 个元素,有 $D(n-1)$ 种方法; 综上得到 $D(n) = (n-1) *(D(n-2) + D(n-1))$ 特殊地,$D(1) = 0, D(2) = 1$. 这就是错排问题。理解了这个,还可以去做一道省选的错排[裸题](https://www.luogu.org/problemnew/show/P3182). 上代码 ``` #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> using namespace std; int f[25],n; int main() { scanf("%d",&n); f[1]=0;f[2]=1;f[3]=2; if(n==1||n==2||n==3) { printf("%d",f[n]); return 0; } for(int i=4;i<=n;i++) { f[i]=(i-1)*(f[i-1]+f[i-2]); } printf("%d",f[n]); return 0; } ```