题解 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);
	}
}
posted @ 2020-02-21 20:01  whx1003  阅读(155)  评论(0编辑  收藏  举报