错排的个数

元素不能在自身位置,这叫做"错排"。

int findDerangement(int n) {
    // 题目:元素k不能在位置k,有多少种排列?
    // https://en.wikipedia.org/wiki/Derangement#Counting_derangements
    // 设dp[i]表示[1..i]的错排数。元素1可以换到位置[2..i],有i-1种选择,比如说换到位置k。
    // 考虑元素k换不换到位置1:如果换到位置1,元素1和k的位置确定,剩下i-2个元素的子问题dp[i-2];
    // 如果不换到位置1,那么考虑"去掉被占位置k外的i-1个位置",元素k在这子问题中成了新的“元素1”;
    // 元素k有个禁止位置为位置1,其他元素也有个禁止位置为自身位置,这就是i-1个元素的子问题dp[i-1]。
    // 所以 dp[i] = (i-1) * (dp[i-2] + dp[i-1])
    // 初始dp[1]=0,dp[0]=1(由dp[2]=1推得)
    // dp[i]只依赖于前两项,降维,用prev2表示dp[i-2],prev1表示dp[i-1]
    const int MOD = 1e9 + 7;
    int prev2 = 1, prev1 = 0;
    for (int i = 2; i <= n; i++) {
        int curr = ((i-1L) * (prev2 + prev1)) % MOD;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}