bzoj4563放棋子

每一行只有一个障碍,每一列也只有一个障碍
可以把某些行交换一下,得到类似下面的格式
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
交换之后并不影响方案数
然后,把每一列压缩成一个位置,问题转化为每一个位置放一个棋子且不能放在原来的位置(第i个个棋子原来的位置是i)
转化为错排公式

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 1000000000
#define LL long long
#define maxn 5005
using namespace std;
int n;
struct Bignum
{
    LL s[maxn];
    int len;
    Bignum(){ memset(s,0,sizeof(s)); len=0; }
}A,B,C;
Bignum operator + (const Bignum a,const Bignum b)
{
    Bignum c;
    int i=1;
    LL x=0;
    while(i<=a.len||i<=b.len)
    {
        c.s[i]=x+a.s[i]+b.s[i];
        x=c.s[i]/mod;
        c.s[i]%=mod;  
        i++;
    }
    c.len=max(a.len,b.len);
    while(x){ c.s[++c.len]=x%mod; x/=mod;}
    while(c.len&&!c.s[c.len]) c.len--;
    return c;
}
Bignum operator *(const Bignum a,int b)
{
    Bignum c;
    c.len=a.len;
    LL x=0;
    for(int i=1;i<=a.len;i++)
    {
       c.s[i]=a.s[i]*(LL)b+x;
       x=c.s[i]/mod;
       c.s[i]%=mod;
    }
    while(x){ c.s[++c.len]=x%mod; x/=mod; }
    while(c.len&&!c.s[c.len]) c.len--;
    return c;
}
void print(Bignum &a)
{
    printf("%lld",a.s[a.len]);
    for(int i=a.len-1;i>=1;i--)
    printf("%09lld",a.s[i]);
    printf("\n");
}
int main()
{
    //freopen("chess_2016.in","r",stdin);
    //freopen("chess_2016.out","w",stdout);
        scanf("%d",&n);
        int x;
        for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++) scanf("%d",&x);
        if(n==1){ printf("0\n"); return 0; }
        if(n==2){ printf("1\n"); return 0; }
        A.len=1; A.s[1]=0; 
        B.len=1; B.s[1]=1; 
        for(int i=3;i<=n;i++)
        { 
            C=(A+B)*(LL)(i-1);
            A=B;
            B=C;
        }
        print(C);
    return 0;
}
posted @ 2017-10-15 21:25  HunterxHunterl  阅读(116)  评论(0编辑  收藏  举报