题目网址

题目大意

  求对于一个长度为n的数组,有多少种方法让所有 a都不等于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;
}