题意: 给你一个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;
}