题目大意:给出n和k,问在n∗n的棋盘上放k个主教互相不攻击能有多少种方法,主教的攻击方式是斜线。
解题思路:将棋盘旋转45度,然后将黑白格子互相分开,因为在国际里面,黑格的主教是永远无法攻击到白格的主教。所以将黑白格分开考虑。
然后对于一种格子的颜色来说,它就类似与在一个棋盘上放车,dp[i][j]表示i行放了j个车,dp[i][j]=dp[i−1][j]+(n−j+1)∗dp[i−1][j],这题的n是可变的,并且还是先增加后减少,但是没事,可以将行数按照长短顺序处理,是不影响结果的。
最后用加法原理,枚举黑格上主教的数量,相加即可。
#include <cstdio>
#include <cstring>
typedef long long ll;
const int N = 40;
int n, k;
ll b[N][N*N], w[N][N*N];
void init () {
memset(b, 0, sizeof(b));
memset(w, 0, sizeof(w));
b[0][0] = w[1][0] = 1;
for (int i = 1; i <= n; i++) {
b[i][0] = b[i-1][0];
int l = (i+1)/2 * 2 - 1;
for (int j = 1; j <= l && j <= k; j++)
b[i][j] = b[i-1][j] + (ll)(l-j+1) * b[i-1][j-1];
}
for (int i = 2; i <= n; i++) {
w[i][0] = w[i-1][0];
int l = i/2 * 2;
for (int j = 1; j <= l && j <= k; j++)
w[i][j] = w[i-1][j] + (ll)(l-j+1) * w[i-1][j-1];
}
}
int main () {
while (scanf("%d%d", &n, &k) == 2 && n + k) {
init();
ll ans = 0;
for (int i = 0; i <= k; i++)
ans = ans + b[n][i] * w[n][k-i];
printf("%lld\n", ans);
}
return 0;
}