题目大意
求对于一个长度为n的数组,有多少种方法让所有 ai 都不等于i
题目分析
设f(n)为n个数的合法排列个数,那么f(1)=0,f(2)=1。
当n>=3时,考虑f(n)的值:
非常明显,把第n个数放在第k个位置上时(k当然不能等于n),有(n-1)中放法;接着,考虑第k个数可能放置的位置:
如果第k个数放置在第n个位置上(这时候ak=n,an=k),那么除n,k以外的(n-2)个数字组成与原问题完全相同的子问题,有f(n-2)种方法;而k有(n-1)种可能,所以有(n-1)*f(n-2)种方法;
如果第k个数不放置在第n个位置上(这时候ak==n 但an≠k),那么除n以外的(n-1)个数字组成与原问题相同的子问题,有f(n-1)种方法;而k仍然有(n-1)种方法,所以又有(n-1)*f(n-1)种方法;
两个式子相加,得f(i)=(i-1)*(f(i-1)+f(i-2));
Code
#include<iostream> #include<cstdio> #define ll long long using namespace std; ll f[30],n; int main(){ scanf("%lld",&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("%lld",f[n]); return 0; }