1. 程式人生 > >bzoj4563 [Haoi2016]放棋子

bzoj4563 [Haoi2016]放棋子

desc it is logs 一行 () 組合數學 cto 發現 algo

Description

給你一個N*N的矩陣,每行有一個障礙,數據保證任意兩個障礙不在同一行,任意兩個障礙不在同一列,要求你在這個矩陣上放N枚棋子(障礙的位置不能放棋子),要求你放N個棋子也滿足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少種方案。

Input

第一行一個N,接下來一個N*N的矩陣。N<=200,0表示沒有障礙,1表示有障礙,輸入格式參考樣例

Output

一個整數,即合法的方案數。

Sample Input

2
0 1
1 0

Sample Output

1

正解:組合數學+高精度。

因為每一行和每一列都只有一個障礙,所以不難發現行和列是可以交換的。

我們把障礙移動到主對角線上,發現答案就是錯排公式。

$f[i]=(f[i-1]+f[i-2])*(i-1)$,直接遞推即可,要寫高精度。

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9
#include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 #define inf (1<<30) 14 #define il inline 15 #define RG register 16 #define ll long long 17 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 18 19 using namespace std;
20 21 int cnt[210],n; 22 ll f[210][1010]; 23 24 25 il int gi(){ 26 RG int x=0,q=1; RG char ch=getchar(); 27 while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 28 if (ch==-) q=-1,ch=getchar(); 29 while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 30 return q*x; 31 } 32 33 il void work(){ 34 n=gi(),f[2][0]=1; 35 for (RG int i=3;i<=n;++i){ 36 cnt[i]=cnt[i-1]; 37 for (RG int j=0;j<=cnt[i];++j) 38 f[i][j]+=f[i-1][j]+f[i-2][j],f[i][j+1]+=f[i][j]/10,f[i][j]%=10; 39 while (f[i][cnt[i]+1]) ++cnt[i]; for (RG int j=0;j<=cnt[i];++j) f[i][j]*=i-1; 40 for (RG int j=0;j<=cnt[i];++j) f[i][j+1]+=f[i][j]/10,f[i][j]%=10; 41 while (f[i][cnt[i]+1]) f[i][cnt[i]+1]+=f[i][cnt[i]]/10,f[i][cnt[i]]%=10,++cnt[i]; 42 } 43 for (RG int i=cnt[n];i>=0;--i) printf("%lld",f[n][i]); return; 44 } 45 46 int main(){ 47 File("chess"); 48 work(); 49 return 0; 50 }

bzoj4563 [Haoi2016]放棋子