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

【BZOJ4563】[Haoi2016]放棋子

Description

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

Input

第一行一个N,接下来一个N*N的矩阵。N<=200,0表示没有障碍,1表示有障碍,输入格式参考样例

Output

一个整数,即合法的方案数。

Sample Input

2
0 1
1 0

Sample Output

1

题解:傻题。

其实只需要读入n就行。因为障碍矩阵可以看成是一个1到n的排列,最后防棋子的位置也可以看成一个1到n的排列。所以答案就是错排的方案数。只需套用错排的经典公式:f[i]=(i-1)*(f[i-1]+f[i-2])。

然而答案不取模,所以用高精度即可。

 

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n;
struct node
{
	int l,v[110];
	node() {memset(v,0,sizeof(v)),l=1;}
	node operator + (const node &a) const
	{
		node b;
		b.l=max(l,a.l);
		for(int i=1;i<=b.l;i++)	b.v[i]+=v[i]+a.v[i],b.v[i+1]=b.v[i]/1000,b.v[i]%=1000;
		if(b.v[b.l+1])	b.l++;
		return b;
	}
	node operator * (const int &a) const
	{
		node b;
		b.l=l;
		for(int i=1;i<=l;i++)	b.v[i]+=v[i]*a,b.v[i+1]=b.v[i]/1000,b.v[i]%=1000;
		if(b.v[b.l+1])	b.l++;
		return b;
	}
}a,b,c;
int main()
{
	scanf("%d",&n);
	if(!n)
	{
		printf("0");
		return 0;
	}
	int i;
	a.l=b.l=a.v[1]=1;
	for(i=1;i<n;i++)	c=a,a=b,b=(c+b)*i;
	printf("%d",b.v[b.l]);
	for(i=b.l-1;i;i--)	printf("%03d",b.v[i]);
	return 0;
}

 

posted @ 2017-11-19 10:41  CQzhangyu  阅读(266)  评论(0编辑  收藏  举报