【JZOJ B组】小A做CF

Description

目标rating超过CLJ的小A最近在疯狂做CF,话说这次CF在赛前十分钟出了个相当奇葩的预选题,要求十分钟内必须做出这道题才能参加这次CF。
这道题是这样的,给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。
最近被各种神题折磨得死去活来,走火入魔的小A一下被这个超级水题给卡住了,但是这次是超过CLJ的最佳机会,于是,心急火燎的他找到了你,请你带他顺利参加这次CF正赛吧。

Input

第一行一个N,接下来一个N*N的矩阵。

Output

合法方案数。

Sample Input

2
0 1
1 0

Sample Output

1

Data Constraint

20%的数据保证: N<=10
60%的数据保证: N<=20
100%的数据保证: N<=200

思路

本题目由于障碍其实是顺序无关的(从每行每列不重复可看出),于是可以将棋盘进行转化

然后可以通过求空白棋盘和有障碍棋盘的方案数,再相乘可得。如果将列位置看成数列的位置,行位置看做数列中的数,显然可以看出棋盘摆棋情况可映射为一个数列,于是有:空白棋盘方案:(全排列)n!带障碍棋盘方案:用错排公式(就是由 n 个人坐座位,然后进行换位,每个人不能坐在原位置的方案数),递推式:f[i]=(i-1)*(f[i-1]+f[i-2])

ps:正解要高精度

代码

#include
#include
using namespace std;
int n;
long long f[500];
int main()
{
	scanf("%d",&n);
	f[1]=0; f[2]=1;
	for(int i=3; i<=n; i++) f[i]=1ll*(i-1)*(f[i-1]+f[i-2]);
	printf("%lld",f[n]);
}

你可能感兴趣的:(题解)