作者:mobiledu2502870747 | 来源:互联网 | 2023-09-11 11:24
【题目描述】
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
【输入格式】
一行n,m(n,m≤100)n, m(n,m\leq100)n,m(n,m≤100)
【输出格式】
一行, 表示方案数(对9999973取模)
SampleInputSample~~InputSample Input
1 3
SampleOutputSample~~OutputSample Output
7
【题意分析】
感谢大佬:顾z
非常像状压,但是100你是压不了的,考虑计数
根据规则转化题意:求每行每列棋子不超过两个的方案数
dp[i][j][k]dp[i][j][k]dp[i][j][k]表示前 iii 行,有 jjj 列放了一个棋子,有 kkk 列放了两个棋子的方案数
那么答案就是∑i=0m∑j=0mdp[n][i][j]\sum\limits_{i=0}^m\sum\limits_{j=0}^mdp[n][i][j]i=0∑mj=0∑mdp[n][i][j]
显而易见当前第 iii 行最多放 222 个棋子,那么我们可以分类讨论了:
- 初始情况
dp[0][0][0]=1dp[0][0][0]=1dp[0][0][0]=1 - 不放任何棋子
继承上一行状态
dp[i][j][k]+=dp[i−1][j][k]dp[i][j][k]+=dp[i-1][j][k]dp[i][j][k]+=dp[i−1][j][k] - 放一个棋子
放在没有棋子的一列,会使 jjj 增加1,所以要寻找 j−1j-1j−1 列的状态
因为放在空列,所以有m−(j−1)−km-(j-1)-km−(j−1)−k种放法
dp[i][j][k]+=dp[i−1][j−1][k]∗(m−(j−1)−k)dp[i][j][k]+=dp[i-1][j-1][k]*(m-(j-1)-k)dp[i][j][k]+=dp[i−1][j−1][k]∗(m−(j−1)−k)放在有一个棋子的一列,会使 kkk 增加1, jjj减少1,所以要寻找j+1,k−1j+1,k-1j+1,k−1的状态
那么有j+1j+1j+1种放法。
dp[i][j][k]+=dp[i−1][j+1][k−1]∗(j+1)dp[i][j][k]+=dp[i-1][j+1][k-1]*(j+1)dp[i][j][k]+=dp[i−1][j+1][k−1]∗(j+1) - 放两个棋子
放在两个空列,会使jjj增加2,所以要寻找j−2j-2j−2的状态
在空列中选两个,即C(m−(j−2)−k)2C_{(m-(j-2)-k)}^{2}C(m−(j−2)−k)2种放法
dp[i][j][k]+=dp[i−1][j−2][k]∗c(m−(j−2)−k,2)dp[i][j][k]+=dp[i-1][j-2][k]*c(m-(j-2)-k,2)dp[i][j][k]+=dp[i−1][j−2][k]∗c(m−(j−2)−k,2)放在一个空列,一个有一个棋子的列,使jjj增加1又减少1,k增加1,所以要寻找j,k−1j,k-1j,k−1的状态
根据乘法原理有j∗(m−j−(k−1))j*(m-j-(k-1))j∗(m−j−(k−1))种放法
dp[i][j][k]+=dp[i−1][j][k−1]∗j∗(m−j−(k−1))dp[i][j][k]+=dp[i-1][j][k-1]*j*(m-j-(k-1))dp[i][j][k]+=dp[i−1][j][k−1]∗j∗(m−j−(k−1))放在两个有一个棋子的列,使kkk增加2,jjj减少2,所以要寻找j+2,k−2j+2,k-2j+2,k−2的状态
在有一个棋子的列种选两个,即Cj+22C_{j+2}^{2}Cj+22种放法
dp[i][j][k]+=dp[i−1][j+2][k−2]∗c(j+2,2)dp[i][j][k]+=dp[i-1][j+2][k-2]*c(j+2,2)dp[i][j][k]+=dp[i−1][j+2][k−2]∗c(j+2,2)
注意边界:对于需要减少的参数,要判断是否大于等于0
别忘了取%
Code:
#include
#include
#include
#include
#include
#include
#include
#define rep(x,y,z) for (register int x &#61; y; x <&#61; z; x&#43;&#43;)
#define MAXN 200
#define qy 9999973
using namespace std;long long dp[MAXN][MAXN][MAXN];inline long long C (int x) {return (long long) (x * (x - 1) / 2) % qy;
} int main () {int n, m; scanf ("%d %d", &n, &m), dp[0][0][0] &#61; 1;rep (i, 1, n) rep (j, 0, m) rep (k, 0, m - j) {dp[i][j][k] &#61; dp[i-1][j][k];if (j >&#61; 1) dp[i][j][k] &#43;&#61; dp[i-1][j-1][k] * (m-(j-1)-k);if (k >&#61; 1) dp[i][j][k] &#43;&#61; dp[i-1][j&#43;1][k-1] * (j&#43;1);if (j >&#61; 2) dp[i][j][k] &#43;&#61; dp[i-1][j-2][k] * C (m-(j-2)-k);if (k >&#61; 2) dp[i][j][k] &#43;&#61; dp[i-1][j&#43;2][k-2] * C (j&#43;2);if (k >&#61; 1) dp[i][j][k] &#43;&#61; dp[i-1][j][k-1] * j * (m-j-(k-1));dp[i][j][k] %&#61; qy;}long long ans &#61; 0;rep (i, 0, m) rep (j, 0, m) ans &#43;&#61; dp[n][i][j], ans %&#61; qy;printf ("%lld", ans);return 0;
}