1026 [HAOI2016]放棋子 组合数学 错位问题

2022/7/29 6:22:57

本文主要是介绍1026 [HAOI2016]放棋子 组合数学 错位问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

链接: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;
} 

 



这篇关于1026 [HAOI2016]放棋子 组合数学 错位问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程