题目大意 多组数据,每组数据给定两个整数 (n,k),输出在 (n imes n) 的棋盘上放置 (k) 个互不攻击的象的不同方式(象攻击两条斜线上的棋子)。
分析 我们把棋盘翻转 (frac{pi}4),会形成一个新的 (2n-1) 行的斜棋盘,那么每个象可以攻击同一行同一列的棋子,发现可以递推答案。
我们考虑先把奇数行和偶数行分开编号讨论,下以奇数行为例。我们从短的行枚举到长的行,用 (f[1][i][j]) 表示奇数行到第 (i) 行一共放了 (j) 个象的总方案数。那么有
[f[1][i][j] = f[1][i-1][j]+f[1][i-1][j-1]*(len_i-j+1)
]
最后统计结果就好了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, k;
ll ans, f[2][65][35];
int main()
{
while(~scanf("%d%d", &n, &k) && !(!n && !k)) {
memset(f, 0, sizeof f);
ans = 0;
f[1][0][0] = f[0][1][0] = 1;
for(int i = 1; i <= n; ++i) {
int len = i - !(i & 1);
f[1][i][0] = 1;
for(int j = 1; j <= len && j <= k; j++)
f[1][i][j] = f[1][i - 1][j] + (len - j + 1) * f[1][i - 1][j - 1];
}
for(int i = 2; i <= n; i++) {
int len = i - (i & 1);
f[0][i][0] = 1;
for(int j = 1; j <= len && j <= k; j++) {
f[0][i][j] = f[0][i - 1][j] + (len - j + 1) * f[0][i - 1][j - 1];
}
}
for(int i = 0; i <= k; i++)
ans += f[1][n][i] * f[0][n][k - i];
printf("%lld
", ans);
}
}