先将棋盘染成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;
}