题解 UVa10237
题目大意 多组数据,每组数据给定两个整数 \(n,k\),输出在 \(n\times 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\n", ans);
}
}