链接:https://ac.nowcoder.com/acm/contest/26656/1026
来源:牛客网
题目描述
给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。
输入描述:
第一行一个N,接下来一个N*N的矩阵。N ≤ 200,0表示没有障碍,1表示有障碍,输入格式参考样例
输出描述:
一个整数,即合法的方案数。
示例1
输入
2 0 1 1 0
输出
1
分析
首先由于n <= 200,所以必须用高精度(太长了)
错位问题。对于第n个位置考虑两种情况:
1.前n个位置已经错位,随便拿一个和最后一个交换即可
2.前n个有一个在自己的位置上,拿最后一个和这个交换即可
递推公式:f[n] = (n – 1) * ( f[n-1] + f[n-2]);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N=2e2+5;
const int ten[4]={1,10,100,1000};
const int max1=1000;
struct BigNumber{
int d[max1];
BigNumber (string s){
int len=s.size();
d[0]=(len-1)/4+1;
for (int i=1;i<max1;i++) d[i]=0;
for (int i=len-1;i>=0;i--){
int j=(len-i-1)/4+1;
int k=(len-i-1)%4;
d[j]+=ten[k]*(s[i]-'0');
}
while (d[0]>1&&d[d[0]]==0) d[0]--;
}
BigNumber(){
*this=BigNumber(string("0"));
}
string toString(){
string s("");
int pos=0;
for (int i=3;i>=1;i--) if (d[d[0]]>=ten[i]) {
pos=i;
break;
}
int temp=d[d[0]];
for (int j=pos;j>=0;j--){
s=s+(char)(temp/ten[j]+'0');
temp%=ten[j];
}
for (int i=d[0]-1;i>0;i--){
temp=d[i];
for (int j=3;j>=0;j--){
s=s+(char)(temp/ten[j]+'0');
temp%=ten[j];
}
}
return s;
}
} zero("0"),one("1"),d,temp,mid1[15];
bool operator < (const BigNumber &a,const BigNumber &b){
if (a.d[0]!=b.d[0])return a.d[0]<b.d[0];
for (int i=a.d[0];i>=0;i--)if (a.d[i]!=b.d[i]) return a.d[i]<b.d[i];
return false;
}
BigNumber operator + (const BigNumber &a, const BigNumber &b){
BigNumber c;
c.d[0]=max(a.d[0],b.d[0]);
int x=0;
for (int i=1;i<=c.d[0];i++){
x=a.d[i]+b.d[i]+x;;
c.d[i]=x%10000;
x/=10000;
}
while (x!=0){
c.d[++c.d[0]]=x%10000;
x/=10000;
}
return c;
}
BigNumber operator - (const BigNumber &a, const BigNumber &b){
BigNumber c;
c.d[0]=a.d[0];
int x=0;
for (int i=1;i<=c.d[0];i++){
x=10000+a.d[i]-b.d[i]+x;
c.d[i]=x%10000;
x=x/10000-1;
}
while ((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--;
return c;
}
BigNumber operator * (const BigNumber &a, const BigNumber &b){
BigNumber c;
c.d[0]=a.d[0]+b.d[0];
int x;
for (int i=1;i<=a.d[0];i++){
x=0;
for (int j=1;j<=b.d[0];j++){
x=a.d[i]*b.d[j]+x+c.d[i+j-1];
c.d[i+j-1]=x%10000;
x/=10000;
}
c.d[i+b.d[0]]=x;
}
while ((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--;
return c;
}
bool smaller(const BigNumber &a, const BigNumber &b, int delta){
if (a.d[0]+delta!=b.d[0]) return a.d[0]+delta<b.d[0];
for (int i=a.d[0];i>0;i--)
if (a.d[i]!=b.d[i+delta]) return a.d[i]<b.d[i+delta];
return true;
}
void Minus (BigNumber &a, BigNumber &b,int delta){
int x=0;
for (int i=1;i<=a.d[0]-delta;i++){
x=10000+a.d[i+delta]-b.d[i]+x;
a.d[i+delta]=x%10000;
x=x/10000-1;
}
while (a.d[0]>1&&a.d[a.d[0]]==0) a.d[0]--;
}
BigNumber operator * (const BigNumber &a, const int &k){
BigNumber c;
c.d[0]=a.d[0];
int x=0;
for (int i=1;i<=a.d[0];i++){
x=a.d[i]*k+x;
c.d[i]=x%10000;
x/=10000;
}
while (x>0){
c.d[++c.d[0]]=x%10000;
x/=10000;
}
while ((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--;
return c;
}
BigNumber operator / (const BigNumber &a, const BigNumber &b){
BigNumber c;
d=a;
mid1[0]=b;
for (int i=1;i<=13;i++){
mid1[i]=mid1[i-1]*2;
}
for (int i=a.d[0]-b.d[0];i>=0;i--){
int temp=8192;
for (int j=13;j>=0;j--){
if (smaller(mid1[j],d,i)){
Minus(d,mid1[j],i);
c.d[i+1]+=temp;
}
temp/=2;
}
}
c.d[0]=max(1,a.d[0]-b.d[0]+1);
while ((c.d[0]>1)&&(c.d[c.d[0]]==0)) c.d[0]--;
return c;
}
bool operator == (const BigNumber &a, const BigNumber &b){
if (a.d[0]!=b.d[0]) return false;
for (int i=1;i<=a.d[0];i++) if (a.d[i]!=b.d[i])return false;
return true;
}
BigNumber fac[N];
BigNumber Comb(int x,int y){
if (x<y) return zero;
return fac[x]/fac[y]/fac[x-y];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n;
cin>>n;
BigNumber ans=zero;
fac[0]=one;
for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i;
for (int i=0;i<=n;i++){
if (i&1) ans=ans-fac[n-i]*Comb(n,i);
else ans=ans+fac[n-i]*Comb(n,i);
}
cout<<ans.toString();
return 0;
}
原创文章,作者:dweifng,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/277628.html