[BZOJ4563][Haoi2016]放棋子

Posted xjr_01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4563][Haoi2016]放棋子相关的知识,希望对你有一定的参考价值。

[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(‘\n‘);
		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;
}

 

以上是关于[BZOJ4563][Haoi2016]放棋子的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4563[Haoi2016]放棋子 错排+高精度

bzoj4563 [Haoi2016]放棋子

BZOJ4563 [Haoi2016]放棋子

[BZOJ 4563][Haoi2016]放棋子(错排公式)

[bzoj4563] [Haoi2016]放棋子

[BZOJ 4563]放棋子