题意:
给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。
题解:⑥
①这道题我们可以分析为错排问题:
一共 1~n n个数,对于任意数x都不在第x个位置上有多少方案数。
②为什么这么说呢(⊙o⊙)?
⑴我们可以注意到:每一行每一列有且只有一个障碍
⑵那么每一行障碍的位置对于答案没有任何实际影响
⑶如果我们按照每一行障碍的位置对行进行排序的话
⑷就转化成了第i行的棋子不能出现在第i个位置的问题
⑸也就是我们上面说的错排问题了
③那么错排问题的公式是什么呢?
f[i]=f[i-1]*(i-1)+f[i-2]*(i-1)
④原理:
⑴第一步,把第i个元素放在一个位置,比如位置k,一共有i-1种方法
⑵第二步,放编号为k的元素,这时有两种情况:
⒈把它放到位置i,那么,对于剩下的i-1个元素,由于第k个元素放到了位置i,剩下i-2个元素就有f[i-2]种方法
⒉第k个元素不把它放到位置i,这时,对于这i-1个元素,有f[i-1]种方法
#include <cstdio> #include <algorithm> #include <cstring> #include <iostream> #include <string.h> using namespace std; struct BigInteger{ int s[1005],len; BigInteger(){ len=0; memset(s,0,sizeof(s)); } BigInteger(const char *A){*this=A;} BigInteger(const int &A){*this=A;} void operator=(const char *A){ len=strlen(A); for(int i=0;i<len;i++) s[i]=A[len-i-1]-'0'; } void operator=(const int &A){ char tmp[1005]; memset(tmp,0,sizeof(tmp)); sprintf(tmp,"%d",A); *this=tmp; } void clear(){ while(len>1 && !s[len-1])len--; } BigInteger operator+(const BigInteger &A){ BigInteger ans; ans.len=max(len,A.len)+1; int Carry=0; for(int i=0;i<len;i++){ ans.s[i]=s[i]+A.s[i]+Carry; Carry=ans.s[i]/10; ans.s[i]%=10; } if(Carry)ans.s[len++]=Carry; ans.clear(); return ans; } void operator+=(const BigInteger &A){ *this=*this+A; } BigInteger operator-(const BigInteger &A){ BigInteger ans; ans=*this; for(int i=0;i<len;i++){ if(ans.s[i]<A.s[i]) ans.s[i]+=10,ans.s[i+1]--; ans.s[i]=ans.s[i]-A.s[i]; } ans.clear(); return ans; } void operator-=(const BigInteger &A){ *this=*this-A; } BigInteger operator-(const int &A){ BigInteger tmp=A; return *this-tmp; } void operator-=(const int &A){ *this=*this-A; } BigInteger operator*(const BigInteger &A){ BigInteger ans; ans.len=len+A.len+1; int Carry=0; for(int i=0;i<len;i++){ Carry=0; for(int j=0;j<A.len;j++){ ans.s[i+j]+=s[i]*A.s[j]+Carry; Carry=ans.s[i+j]/10; ans.s[i+j]%=10; } ans.s[i+A.len]+=Carry; } ans.clear(); return ans; } void operator*=(const BigInteger &A){ *this=*this*A; } BigInteger operator*(const int &A){ BigInteger tmp=A; return *this*tmp; } void operator*=(const int &A){ *this=*this*A; } void Print(){ for(int i=len-1;i>=0;i--) printf("%d",s[i]); printf(" "); } }f[205]; int main(){ int n;scanf("%d",&n); f[0]=1; f[1]=0; for(int i=2;i<=n;i++) f[i]=(f[i-1]+f[i-2])*(i-1); f[n].Print(); return 0; }