题意:
给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。

思路: 假设我们把每行障碍上的那个元素 当做 元素本来就在的位置。

那么题意就是让其全部错位---没有一个元素是在他原本的位置上

我们处理这样一个数组f[n]表示n个数错排的方案数

f[n] = (f[n-1] + f[n-2])*(n-1)
f[1] = 0
f[2] = 1

由于n为200,并且题目没有要求取模,所以我们要需要敲一个高精度的板子。

code

#include<bits/stdc++.h> 
#define N 205
using namespace std;

int n;

struct BigInteger{
    vector<int> a;
    BigInteger(){ a.clear(); }
    BigInteger operator = (long long num){
        a.clear();
        do{
            a.push_back(num % 10);
            num /= 10;
        }while(num);
        return *this;
    }
    BigInteger operator + (const BigInteger& B) const{
        BigInteger C;
        for(int i = 0, g = 0; ; i++){
            if(g == 0 && i >= a.size() && i >= B.a.size())  break;
            int x = g;
            if(i < a.size())    x += a[i];
            if(i < B.a.size())  x += B.a[i];
            C.a.push_back(x % 10);
            g = x / 10;
        }
        return C;
    }
    BigInteger operator * (const BigInteger& B) const{
        BigInteger C;
        C.a.resize(a.size() + B.a.size());
        for(int i = 0; i < a.size(); i++){
            int g = 0;
            for(int j = 0; j < B.a.size(); j++){
                C.a[i+j] += a[i] * B.a[j] + g;
                g = C.a[i+j] / 10;
                C.a[i+j] %= 10;
            }
            C.a[i+B.a.size()] = g;
        }
        while(C.a.size() > 1 && C.a.back() == 0)    C.a.pop_back();
        return C;
    }
}f[N], t;

void print(BigInteger x){
    for(int i = x.a.size() - 1; i >= 0; i--)
        printf("%d", x.a[i]);
}

int main(){
    cin>>n;
    f[1] = 0ll,;
    f[2] = 1ll;
    for(int i = 3; i <= n; i++){
        t = i - 1ll;
        f[i] = (f[i-1] + f[i-2]) * t;
    }
    print(f[n]);
    return 0;
}