[BZOJ4563][Haoi2016]放棋子
试题描述
给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。
输入
第一行一个N,接下来一个N*N的矩阵。N<=200,0表示没有障碍,1表示有障碍,输入格式参考样例
输出
一个整数,即合法的方案数。
输入示例
2 0 1 1 0
输出示例
1
数据规模及约定
见“输入”
题解
我们发现交换两行不会影响结果,于是任意一个合法的矩阵通过交换都能变成主对角线为 1 其余为 0 的矩阵。
然后对于第 i 行我们确定一个位置 Pi,满足 Pi ≠ i,求有多少种方案。这其实就是一个经典的错位排序问题。
我们考虑对于 Pn,令 Pn = x。接下来分情况讨论,若 Px = n,那么就是剩下的 n - 2 个数错位排序;若 Px ≠ n,那么如果把 n 想象成原来的 x,就是要确定 P1 到 Pn-1 的值,即一个 n - 1 个数的错位排序。由于 Pn 有 n - 1 种取法,得到递推式 F(n) = (F(n-1) + F(n-2)) * (n - 1).
写(贴)个高精度模板就好了。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } struct LL { int len, A[510]; LL() { len = -1; } LL(int x) { A[1] = x; len = 1; if(x) while(A[len] > 9) A[len+1] = A[len] / 10, A[len] %= 10, len++; else len = -1; } LL operator = (const int& t) { A[1] = t; len = 1; if(t) while(A[len] > 9) A[len+1] = A[len] / 10, A[len] %= 10, len++; else len = -1; return *this; } LL operator + (const LL& t) const { LL ans; ans.len = max(len, t.len); for(int i = 1; i <= ans.len; i++) ans.A[i] = (i <= len ? A[i] : 0) + (i <= t.len ? t.A[i] : 0); for(int i = 1; i < ans.len; i++) if(ans.A[i] > 9) ans.A[i+1] += ans.A[i] / 10, ans.A[i] %= 10; while(ans.A[ans.len] > 9) ans.A[ans.len+1] = ans.A[ans.len] / 10, ans.A[ans.len] %= 10, ans.len++; return ans; } LL operator += (const LL& t) { *this = *this + t; return *this; } LL operator + (const int& t) const { LL ans; ans.len = max(len, 1); for(int i = 1; i <= ans.len; i++) ans.A[i] = A[i]; ans.A[1] += t; for(int i = 1; i < ans.len; i++) if(ans.A[i] > 9) ans.A[i+1] += ans.A[i] / 10, ans.A[i] %= 10; while(ans.A[ans.len] > 9) ans.A[ans.len+1] = ans.A[ans.len] / 10, ans.A[ans.len] %= 10, ans.len++; return ans; } LL operator += (const int& t) { *this = *this + t; return *this; } LL operator ++ () { // ++this; *this = *this + 1; return *this; } LL operator ++ (int x) { // this++; *this = *this + 1; return *this - 1; } LL operator - (const LL& t) const { if(t.len < 0) return *this; LL ans; ans.len = max(len, t.len); for(int i = 1; i <= ans.len; i++) ans.A[i] = A[i] - t.A[i]; for(int i = 1; i < ans.len; i++) if(ans.A[i] < 0) { int tmp = (-ans.A[i] + 9) / 10; ans.A[i+1] -= tmp; ans.A[i] += tmp * 10; } while(!ans.A[ans.len]) ans.len--; return ans; } LL operator -= (const LL& t) { *this = *this - t; return *this; } LL operator - (const int& t) const { LL ans; ans.len = len; for(int i = 1; i <= ans.len; i++) ans.A[i] = A[i]; ans.A[1] -= t; for(int i = 1; i < ans.len; i++) if(ans.A[i] < 0) { int tmp = (-ans.A[i] + 9) / 10; ans.A[i+1] -= tmp; ans.A[i] += tmp * 10; } while(!ans.A[ans.len]) ans.len--; return ans; } LL operator -= (const int& t) { *this = *this - t; return *this; } LL operator -- () { // --this; *this = *this - 1; return *this; } LL operator -- (int x) { // this--; *this = *this - 1; return *this + 1; } LL operator * (const LL& t) const { LL ans; ans.len = len + t.len - 1; if(len < 0 || t.len < 0) return ans.len = -1, ans; for(int i = 1; i <= ans.len; i++) ans.A[i] = 0; for(int i = 1; i <= len; i++) for(int j = 1; j <= t.len; j++) ans.A[i+j-1] += A[i] * t.A[j]; for(int i = 1; i < ans.len; i++) if(ans.A[i] > 9) ans.A[i+1] += ans.A[i] / 10, ans.A[i] %= 10; while(ans.A[ans.len] > 9) ans.A[ans.len+1] = ans.A[ans.len] / 10, ans.A[ans.len] %= 10, ans.len++; return ans; } LL operator *= (const LL& t) { *this = *this * t; return *this; } LL operator * (const int& t) const { LL ans = t; return ans * (*this); } LL operator *= (const int& t) { *this = *this * t; return *this; } bool operator < (const LL& t) const { if(len != t.len) return len < t.len; for(int i = len; i > 0; i--) if(A[i] != t.A[i]) return A[i] < t.A[i]; return 0; } bool operator > (const LL& t) const { if(len != t.len) return len > t.len; for(int i = len; i > 0; i--) if(A[i] != t.A[i]) return A[i] > t.A[i]; return 0; } bool operator == (const LL& t) const { if(len != t.len) return 0; for(int i = len; i > 0; i--) if(A[i] != t.A[i]) return 0; return 1; } bool operator != (const LL& t) const { return !((*this) == t); } bool operator <= (const LL& t) const { return *this < t || *this == t; } bool operator >= (const LL& t) const { return *this > t || *this == t; } LL operator / (const LL& t) const { LL ans, f = 0; ans.len = -1; for(int i = 1; i <= len; i++) ans.A[i] = 0; for(int i = len; i > 0; i--) { f = f * 10 + A[i]; while(f >= t) { f -= t; ans.A[i]++; ans.len = max(ans.len, i); } } return ans; } LL operator /= (const LL& t) { *this = *this / t; return *this; } LL operator / (const int& t) const { LL ans; int f = 0; ans.len = -1; for(int i = 1; i <= len; i++) ans.A[i] = 0; for(int i = len; i > 0; i--) { f = f * 10 + A[i]; while(f >= t) { f -= t; ans.A[i]++; ans.len = max(ans.len, i); } } return ans; } LL operator /= (const int& t) { *this = *this / t; return *this; } void print() { if(len < 0){ putchar('0'); return ; } for(int i = len; i > 0; i--) putchar(A[i] + '0'); putchar(' '); return ; } }; #define maxn 210 LL f[maxn]; int main() { int n = read(); for(int i = 1; i <= n * n; i++) read(); f[1] = 0; f[2] = 1; for(int i = 3; i <= n; i++) f[i] = (f[i-2] + f[i-1]) * (i - 1); f[n].print(); return 0; }