1 条题解
-
1
题意分析
题目大意:
给定一个 的矩阵,已知:
. 每行的和
. 每列的和 要求计算满足这些条件的非负整数矩阵的数量,结果对 取模。如果行列和不匹配(即,直接输出。
关键点分析:
. 行列和必须相等:若,无解。
. 动态分配问题:每行的三个数 需要满足:
所有行的之和为之和为之和为。
解题思路
方法选择:
这是一个典型的多维动态规划(DP)问题,状态表示已分配的部分列和,逐步填充矩阵的行。
状态定义:
设表示: . 已填充的 列和为
. 已填充的 列和为
. 则 列和为_(由行列和相等保证)
转移方程:
对于每一行,枚举其可能的分配:
.
.(剩余可分配的 列和)
. (剩余可分配的 列和)
. _(剩余可分配的 列和)
更新状态:
_
初始化:
(未填充任何行列时的初始状态)
结果:
最终答案为 (所有列和恰好分配完毕)。
标程:
#include <iostream> #include <vector> #include <algorithm> // 包含min函数 #include <utility> // 包含move函数 using namespace std; typedef long long ll; const ll MOD = 100000000000000000LL; // 1e17的精确表示 int main() { int n, c1, c2, c3; cin >> n >> c1 >> c2 >> c3; vector<int> row(n); int total_row = 0; for (int i = 0; i < n; ++i) { cin >> row[i]; total_row += row[i]; } if (total_row != c1 + c2 + c3) { cout << 0 << endl; return 0; } // dp[a][b]表示已分配c1列和a、c2列和b时的方案数 vector<vector<ll> > dp(c1+1, vector<ll>(c2+1, 0)); dp[0][0] = 1; for (int r = 0; r < n; ++r) { int s = row[r]; vector<vector<ll> > new_dp(c1+1, vector<ll>(c2+1, 0)); for (int a = 0; a <= c1; ++a) { for (int b = 0; b <= c2; ++b) { if (dp[a][b] == 0) continue; // 枚举当前行给三列的分配量 for (int x = 0; x <= min(s, c1 - a); ++x) { for (int y = 0; y <= min(s - x, c2 - b); ++y) { int z = s - x - y; if (z < 0 || z > c3) continue; new_dp[a + x][b + y] = (new_dp[a + x][b + y] + dp[a][b]) % MOD; } } } } dp = new_dp; // 直接赋值替代move,兼容性更好 } cout << dp[c1][c2] << endl; return 0; }
- 1
信息
- ID
- 1103
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者