BZOJ4563[Haoi2016]放棋子
题目描述 Description
|
给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在
这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋的限制,求有多少种方案。
|
输入描述 Input Description
|
第一行一个N,接下来一个N*N的矩阵。N<=200,0表示没有障碍,1表示有障碍,输入格式参考样例 |
输出描述 Output Description
|
一个整数,即合法的方案数。
|
样例输入 Sample Input
|
2
0 1 1 0 |
样例输出 Sample Output
|
1
|
数据范围及提示 Data Size & Hint
|
|
仔细读完题发现输入的那个矩阵一点用也没有,因为可以通过平移变成障碍全在对角线上的图。继续来思考这个问题,问题转化为将1~n这N个数排列,要求第i个数不能排列在第i个位置上,这被称之为错排问题。考虑怎么递推。设f(i)表示i个数的错拍方案数,我们要将第i个数插入之前i-1个数,(因为第i个数不能插在i位置上),假如i将插在j位置上,j有两种选择,一种是j填到i的位置上,于是问题就转化为了f(i-2);另一种j填到另外i-2的位置中,我们设新填的位置为k(k!=i && k!=j),现在我们就需要把k这个数再放在i-1个数中了,即f(i-1),由于j有i-1种情况,所以我们最后再乘一个(i-1),所以递推公式就变成了f(i)=(f(i-1)+f(i-2))*(i-1),推到这一步,我们再写一个高精度支持高加高,高乘低即可。
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<cmath> #include<cstring> using namespace std; typedef long long LL; typedef pair<int,int> PII; #define mem(a,b) memset(a,b,sizeof(a)) inline 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; } const int maxn=1010; struct data { int l,v[maxn]; data(){l=1;mem(v,0);} data operator = (const int& s) { v[1]=s; while(v[l]>9)v[l+1]=v[l]/10,v[l]%=10,l++; return *this; } data operator = (const data& s) { l=s.l; for(int i=1;i<=l;i++)v[i]=s.v[i]; return *this; } data operator + (const data& s)const { data c;c.l=max(l,s.l)+1; for(int i=1;i<=c.l;i++)c.v[i]=v[i]+s.v[i]; for(int i=1;i<c.l;i++)if(c.v[i]>9)c.v[i+1]+=c.v[i]/10,c.v[i]%=10; while(c.v[c.l]>9)c.v[c.l+1]=c.v[c.l]/10,c.v[c.l]%=10,c.l++; while(!c.v[c.l])c.l--; return c; } data operator * (const int& s)const { data c;c.l=l; for(int i=1;i<=c.l;i++)c.v[i]=v[i]*s; for(int i=1;i<c.l;i++)if(c.v[i]>9)c.v[i+1]+=c.v[i]/10,c.v[i]%=10; while(c.v[c.l]>9)c.v[c.l+1]=c.v[c.l]/10,c.v[c.l]%=10,c.l++; while(!c.v[c.l])c.l--; return c; } }f[210]; void print(data a){for(int i=a.l;i;i--)printf("%d",a.v[i]);} int n; int main() { n=read(); f[1]=0;f[2]=1; for(int i=3;i<=n;i++)f[i]=(f[i-1]+f[i-2])*(i-1); print(f[n]); return 0; }