HDU 1465 :不容易系列之一(错排问题,二项式反演)

HDU 1465 :不容易系列之一(错排问题,二项式反演)_第1张图片


从题意来看,就是求 n 个人的错排方案数
考虑递推的方法: n n n 个人错排, n n n 一定不在自己位置上,考虑 n n n 站在 其它 n − 1 n - 1 n1 个人中某一个人的位置,显然这样能将所有情况分成不相交的情况。
假设 n n n 站在了 i i i 的位置上,那么根据 i i i 是否站在 n n n 的位置上可以再将情况分成两种:
1: i i i 不在 n n n 的位置上,这相当于 n − 1 n - 1 n1个数错排, i i i 不能在 n n n 的位置。
2: i i i n n n 的位置上,那么剩下 n − 2 n - 2 n2个数错排即可
因此递推式为: d [ n ] = ( n − 1 ) ∗ ( d [ n − 1 ] + d [ n − 2 ] ) d[n] = (n - 1) * (d[n - 1] + d[n - 2]) d[n]=(n1)(d[n1]+d[n2]),边界值为: d [ 0 ] = d [ 1 ] = 0 , d [ 2 ] = 1 d[0] = d[1] = 0,d[2] = 1 d[0]=d[1]=0,d[2]=1
这个递推式是非常系数的递推式

另外一种做法是用容斥原理 n n n 个人任意排列:方案有 n ! n! n!
扣掉一个人站在自己的位置上,其它 n − 1 n - 1 n1个人任意排列: n ! − C ( n , 1 ) ∗ ( n − 1 ) ! n! - C(n,1) * (n - 1)! n!C(n,1)(n1)!

很容易得到容斥计算公式: ∑ i = 0 n ( − 1 ) i C ( n , i ) ( n − i ) ! \sum_{i = 0}^n(-1)^iC(n,i)(n-i)! i=0n(1)iC(n,i)(ni)!

学了二项式反演之后,然后现在又有了一种憨憨做法
f ( i ) f(i) f(i)为 恰有 i i i 个人错排, F ( i ) F(i) F(i) 为最多 i 个人错排,显然 F ( i ) = i ! F(i) = i! F(i)=i!

F ( n ) = ∑ i = 0 n C ( n , i ) f ( i ) F(n) = \sum_{i = 0}^nC(n,i)f(i) F(n)=i=0nC(n,i)f(i)
反演一下有 f ( n ) = ∑ i = 0 n ( − 1 ) n − i C ( n , i ) F ( i ) = ∑ i = 0 n ( − 1 ) n − i C ( n , i ) i ! f(n) = \sum_{i = 0}^n(-1)^{n-i}C(n,i)F(i) =\sum_{i = 0}^n(-1)^{n-i}C(n,i)i! f(n)=i=0n(1)niC(n,i)F(i)=i=0n(1)niC(n,i)i!
形式上和容斥原理相同。

那么还是给个递推的代码吧(逃


代码:

#include
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10; 
ll dp[maxn];
int main() {
	dp[0] = dp[1] = 0;dp[2] = 1;
	for(int i = 3; i <= 20; i++)
		dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]);
	int n;
	while(scanf("%d",&n) != EOF) {
		printf("%lld\n",dp[n]);
	}
	return 0;
}

你可能感兴趣的:(二项式反演,错排问题)