数学专项counting:UVa 10237

先将棋盘染成2种颜色,可以发现可以将棋盘的格子分成2种互不相关的类型。每种类型按对角线长度的奇偶性分类,同一类型的行列不能出现多个bishop。为了递推,可以将所有行按升序排列。

f1[i][j]表示对角线长度为奇数的第i行有j个bishop的方案数;

f2[i][j]表示对角线长度为偶数的第i行有j个bishop的方案数。

递推式为f[i][j]=f[i-1][j]+(c-j+1)*f[i-1][j-1],c为i行的格子数。

f1,f2均可预处理出来,然后结果即为sum{f1[n][i]*f2[n][k-i]|0<=i<=k}。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn=40;
int n,k;
LL f1[maxn][maxn*maxn],f2[maxn][maxn*maxn];
void init()
{
    memset(f1,0,sizeof(f1));
    memset(f2,0,sizeof(f2));
    f1[0][0]=1;
    for(int i=1;i<=30;i++)
    {
        int c=(i%2)?i:i-1;
        for(int j=0;j<=i;j++)
        {
            f1[i][j]=f1[i-1][j];
            if(j) f1[i][j]+=(c-j+1)*f1[i-1][j-1];
        }
    }
    f2[0][0]=1;
    for(int i=1;i<=30;i++)
    {
        int c=(i%2)?i+1:i;
        for(int j=0;j<=i;j++)
        {
            f2[i][j]=f2[i-1][j];
            if(j) f2[i][j]+=(c-j+1)*f2[i-1][j-1];
        }
    }
}
int main()
{
   // freopen("in.txt","r",stdin);
    init();
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(!n && !k) break;
        LL ans=0;
        for(int i=0;i<=k;i++)
        {
            //cout<<i<<" "<<k-i<<" "<<f1[n][i]<<" "<<f2[n-1][k-i]<<endl;
            ans+=f1[n][i]*f2[n-1][k-i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值