可可西里

Description

如果假设一个藏羚羊群体有N只羊,就可以把它们的领地当做一个N*N的方阵,在这个方阵上第I列的第I行都有一个圣地,它们不会居住在圣地,同时每行每列只能居住一只羚羊。于是他们很快算出一个有N只羊的藏羚羊群体的居住地分布方法数。

Analysis

如果不考虑圣地的因素干扰,这题很容易写出动规方程:

dp[i]=dp[i-1]*i

什么意思呢?就是对于n·n的方阵由(n-1)·(n-1)转移而来,原先的行和列都已经占满,所以第n只绵羊只能放在新增的列和行上,新增的列当然是第n列,而新增的行可以放在n·n方阵的任意一行,共n种情况。

然而 圣地的存在限制了绵羊的放置,对于n·n方阵,显然的我们只需要考虑第n列绵羊的防治,它只能放在1~n-1行,放置之后,将原方阵切割,再合并之后可以看做(n-1)·(n-1)矩形。

4·4原图:

放在第四列第一行后:

舍去无法放置的区域后:

放在第四列第二行后可以画出:

等效替换后,发现他们都可以表示为(n-1)·(n-1)方阵下最后一行无圣地的情况,令无圣地情况为dp[n-1][1],那么dp[n][0]=dp[n-1][1]·(n-1)。

而此特殊情况如何计算呢?显然对于前n-1行处理方式与普通情况是一样的,只是最后一行又多了dp[i-1][0]种情况。

dp[i][0]=dp[i-1][1]*(n-1)

dp[i][1]=dp[i-1][0]+dp[i][0]

因为数据太大,需要使用高精度。

Code


#include <bits/stdc++.h>

struct bigint{
    int len,num[5010];
    bigint operator = (int eq){
        len=0;
        memset(num,0,sizeof(num));
        while(eq){
            num[len++]=eq%10;
            eq/=10;
        }
        return *this;
    }
    bigint operator = (bigint eq){
        len=eq.len;
        memset(num,0,sizeof(num));
        for(int i=0;i<len;i++)
            num[i]=eq.num[i];
        return *this;
    }
    bigint operator + (bigint ad){
        bigint ans;
        ans.len=std::max(len,ad.len);
        memset(ans.num,0,sizeof(ans.num));
        int add=0;
        for(int i=0;i<ans.len;i++){
            int res=num[i]+ad.num[i]+add;
            ans.num[i]=res%10;
            add=res/10;
        }
        if(add)ans.num[ans.len++]=add;
        return ans;
    }
    bigint operator * (int mt){
        bigint ans;
        ans.len=len;
        memset(ans.num,0,sizeof(ans.num));
        for(int i=0;i<len;i++)
            ans.num[i]=num[i]*mt;
        int add=0;
        for(int i=0;i<len;i++){
            ans.num[i]+=add;
            add=ans.num[i]/10;
            ans.num[i]%=10;
        }
        while(add){
            ans.num[ans.len++]=add%10;
            add/=10;
        }
        return ans;
    }
    friend std::ostream& operator << (std::ostream& out,bigint ans){
        for(int i=ans.len-1;i+1;i--)
            out<<ans.num[i];
        return out;
    }
};

int n;
bigint dp[1010][2];

int main(){
    freopen("keke.in","r",stdin);
    freopen("keke.out","w",stdout);
    std::cin>>n;
    dp[1][0]=0;
    dp[1][1]=1;
    for(int i=2;i<=n;i++)
            dp[i][0]=dp[i-1][1]*(i-1),dp[i][1]=dp[i][0]+dp[i-1][0];
    std::cout<<dp[n][0]<<std::endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qswx/p/9492772.html