1. 程式人生 > >【JZOJ B組】小A做CF

【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<iostream>
#include<cstdio>
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]);
}