动态规划
普通矩阵快速幂
// ============================================================
// 普通矩阵 + 矩阵快速幂模板(模 MOD)
// ============================================================
// 当前支持:
// 1. 任意行列矩阵
// 2. 矩阵加法、减法、乘法
// 3. 单位矩阵 Matrix::identity(n)
// 4. 方阵快速幂 qpow(base, exp)
// 5. 矩阵乘列向量 multiply_vector(v)
//
// 默认语义:
// 普通模意义矩阵乘法:
// C[i][j] = sum(A[i][k] * B[k][j]) % MOD
// 下标从 0 开始。
//
// 换题时常见改动:
// 1. 固定小矩阵且特别卡常:把 vector 改成静态数组 int a[N][N]。
// 2. 不取模:删除 norm() 和所有 % MOD,但要检查是否会溢出。
// 3. MOD 不是全局常量:可以给 Matrix 增加成员 mod,并保证参与运算的矩阵 mod 相同。
// 4. max-plus / min-plus:不能只把 MOD 删除。
// max-plus 要把“加法”改为 max,把“乘法”改为 +,
// 单位矩阵对角线为 0,其余位置为负无穷。
// 当前目录已有“矩阵快速幂 max-plus.cpp”作为对应示例。
// 5. 行向量转移通常写 old_dp * trans;列向量转移通常写 trans * old_dp。
// 建转移矩阵前一定先确定自己采用哪种方向。
//
// 注意:
// - qpow 只接受方阵。
// - 默认依赖外部的 constexpr int MOD。
// - 在 #define int long long 的代码风格下,两个模数内元素相乘通常可放入 long long;
// 如果 MOD 更大,乘法应改用 __int128。
// ============================================================
class Matrix
{
private:
int row, col;
vector<vector<int>> a;
int norm(int x) const
{
x %= MOD;
if (x < 0)
{
x += MOD;
}
return x;
}
public:
Matrix(int row = 0, int col = 0, int val = 0)
: row(row), col(col), a(row, vector<int>(col, norm(val)))
{
}
Matrix(const vector<vector<int>> &v)
: row(v.size()), col(v.empty() ? 0 : v[0].size()), a(v)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
a[i][j] = norm(a[i][j]);
}
}
}
static Matrix identity(int n)
{
Matrix ans(n, n);
for (int i = 0; i < n; i++)
{
ans[i][i] = 1;
}
return ans;
}
vector<int> &operator[](int i)
{
return a[i];
}
const vector<int> &operator[](int i) const
{
return a[i];
}
int rows() const
{
return row;
}
int cols() const
{
return col;
}
Matrix operator+(const Matrix &other) const
{
Matrix ans(row, col);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
ans[i][j] = norm(a[i][j] + other[i][j]);
}
}
return ans;
}
Matrix operator-(const Matrix &other) const
{
Matrix ans(row, col);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
ans[i][j] = norm(a[i][j] - other[i][j]);
}
}
return ans;
}
Matrix operator*(const Matrix &other) const
{
Matrix ans(row, other.col);
for (int i = 0; i < row; i++)
{
for (int k = 0; k < col; k++)
{
if (a[i][k] == 0)
{
continue;
}
for (int j = 0; j < other.col; j++)
{
ans[i][j] = (ans[i][j] + a[i][k] * other[k][j]) % MOD;
}
}
}
return ans;
}
Matrix &operator+=(const Matrix &other)
{
return *this = *this + other;
}
Matrix &operator-=(const Matrix &other)
{
return *this = *this - other;
}
Matrix &operator*=(const Matrix &other)
{
return *this = *this * other;
}
vector<int> multiply_vector(const vector<int> &v) const
{
vector<int> ans(row);
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
ans[i] = (ans[i] + a[i][j] * norm(v[j])) % MOD;
}
}
return ans;
}
};
Matrix qpow(Matrix base, int exp)
{
Matrix ans = Matrix::identity(base.rows());
while (exp)
{
if (exp & 1)
{
ans *= base;
}
base *= base;
exp >>= 1;
}
return ans;
}
0/1 与完全背包
// 0/1 背包:每件物品最多一次,容量不超过 W。
vector<long long> zero_one_knapsack(
int W, const vector<pair<int, int>>& items) {
vector<long long> dp(W + 1);
for (auto [weight, value] : items)
for (int j = W; j >= weight; --j)
dp[j] = max(dp[j], dp[j - weight] + value);
return dp;
}
// 完全背包:每件物品可用任意次。
vector<long long> complete_knapsack(
int W, const vector<pair<int, int>>& items) {
vector<long long> dp(W + 1);
for (auto [weight, value] : items)
for (int j = weight; j <= W; ++j)
dp[j] = max(dp[j], dp[j - weight] + value);
return dp;
}