【洛谷】P1595 信封问题(配数学证明)

题目地址:

https://www.luogu.com.cn/problem/P1595

题目描述:
某人写了 n n n封信和 n n n个信封,如果所有的信都装错了信封,求所有信都装错信封共有多少种不同情况。

输入格式:
一个信封数 n n n,保证 n ≤ 20 n \le 20 n20

输出格式:
一个整数,代表有多少种情况。

数据范围:
对于 100 % 100 \% 100%的数据, 1 ≤ n ≤ 20 1 \le n \le 20 1n20

f [ n ] f[n] f[n]是有 n n n个信封的时候的错排数,则 f [ 1 ] = 0 , f [ 2 ] = 1 f[1]=0, f[2]=1 f[1]=0,f[2]=1。考虑 f [ n ] f[n] f[n],分步骤做,先将第 1 1 1个信封放在第 k k k个位置,那么有 n − 1 n-1 n1种放法(不能放 1 1 1号位,别的位置都可以),接下来考虑第 k k k个信封放在了哪儿,第一种情况,它可以放在 1 1 1号位,那么剩余位置是 n − 2 n-2 n2个元素的错排,方案数为 f [ n − 2 ] f[n-2] f[n2];第二种情况,它可以放在除了 1 1 1号位以外的位置,那么可以将这个 k k k号信封也视为 1 1 1号信封,则方案数为 n − 1 n-1 n1个元素的错排,即 f [ n − 1 ] f[n-1] f[n1];由加法原理,固定 k k k后,方案数为 f [ n − 2 ] + f [ n − 1 ] f[n-2]+f[n-1] f[n2]+f[n1],再由乘法原理, f [ n ] = ( n − 1 ) ( f [ n − 2 ] + f [ n − 1 ] ) f[n]=(n-1)(f[n-2]+f[n-1]) f[n]=(n1)(f[n2]+f[n1])代码如下:

#include <iostream>
using namespace std;
const int N = 30;
int n;
long f[N];

int main() {
  scanf("%d", &n);
  f[1] = 0, f[2] = 1;
  for (int i = 3; i <= n; i++)
    f[i] = (i - 1) * (f[i - 1] + f[i - 2]);
  printf("%ld\n", f[n]);
}

时空复杂度 O ( n ) O(n) O(n)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值