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;
}
View Code

 

posted @ 2017-05-29 17:16  小飞淙的云端  阅读(248)  评论(0编辑  收藏  举报