QuadraticForm - 题解
标签与难度
标签: 线性代数, 矩阵, 高斯消元, 拉格朗日乘数法, 最优化问题, 数学 难度: 2200
题目大意喵~
主人你好呀,这道题是说,我们有一个 的正定矩阵 和一个 维向量 。我们需要找到一个 维实数向量 ,它需要满足一个不等式约束:
同时,要让另一个线性表达式的值最大化:
题目告诉我们,这个最大值的平方,也就是 ,一定可以表示成一个分数 。我们的任务就是计算 的值,喵~
用矩阵的语言来描述一下就是:
- 约束条件:
- 优化目标:最大化
我们要找到这个最大值的平方,并在模意义下输出结果,呐。
解题思路分析
这道题看起来充满了复杂的数学公式,但别怕,让我一步步带你解开它的神秘面纱,喵~
第一步:理解问题本质
这是一个经典的约束最优化问题。我们想在由 定义的一个 维空间中的“椭球体”内部或边界上,找到一个点 ,使得它在向量 方向上的投影最远(也就是 最大)。
直觉上,这个最大值点肯定是在椭球的边界上取得的,对吧?如果在内部,我们总可以再向 的方向挪动一小步,让 的值变得更大,同时还不会跑出椭球。所以,我们的约束条件可以收紧为等式:
第二步:处理二次型与矩阵对称性
表达式 叫做二次型。这里有一个小技巧哦!对于任何方阵 ,二次型的值都只和它的对称部分有关。我们可以把 分解成一个对称矩阵 和一个反对称矩阵 的和,。
其中 是 的转置矩阵。对于任何向量 ,都有 。所以:
这意味着,约束 其实等价于 。 是一个对称矩阵,处理起来会方便很多!
所以,我们的问题转化为了:
- 约束条件:,其中
- 优化目标:最大化
第三步:拉格朗日乘数法登场!
对于这种带等式约束的优化问题,拉格朗日乘数法是我们的超级武器,喵!我们构造一个拉格朗日函数 :
其中 是拉格朗日乘子。为了找到极值点,我们让 对 的梯度(所有偏导数组成的向量)为零向量:
计算梯度:
- (因为 是对称的)
所以梯度方程是:
因为 是正定的,所以它的对称部分 也是正定的,这意味着 是可逆的。我们可以解出 :
第四步:求解与化简
我们得到了 的表达式,但它还依赖于未知的 。别急,我们还有约束条件 没用呢!把 的表达式代入约束中:
因为 且 对称 (),所以 。
现在我们知道了 的值。我们再来看看我们的目标函数 :
我们要求的是 ,那就平方一下:
把刚才求出的 代入分母:
哇!经过一番推导,我们得到了一个超级简洁的结论!我们要求的答案就是 。
第五步:制定算法
现在,任务就很明确了,就是计算 。
- 构造矩阵 : 。在模运算下,除以2等于乘以2的逆元。所以 。
- 计算 : 我们不想直接求出 这个大矩阵,太慢啦。我们可以把 看作是线性方程组 的解。
- 求解线性方程组: 我们可以用高斯消元法来解方程组 ,得到向量 。
- 计算最终结果: 有了 之后,我们要求的 就是 。
计算这个点积,然后取模,就是最终答案啦!
总结一下我们的最终算法:
- 根据输入的 构造矩阵 。
- 构造增广矩阵 。为什么是 ?因为我们想解的方程是 ,即 , 这等价于 。
- 使用高斯消元法求解线性方程组 ,得到解向量 。
- 计算最终答案 。
这样是不是清晰多啦?喵~ 让我们把这个思路变成代码吧!
代码实现
这是我根据上面的思路,精心重构的代码哦!注释超级详细,希望能帮到你,喵~
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
// 使用 long long 防止计算过程中溢出
using ll = long long;
const int MOD = 998244353;
// 快速幂函数,用于计算 a^b % MOD
// 在这里主要用来求逆元,即 a^(MOD-2) % MOD
ll power(ll base, ll exp) {
ll res = 1;
base %= MOD;
while (exp > 0) {
if (exp % 2 == 1) res = (res * base) % MOD;
base = (base * base) % MOD;
exp /= 2;
}
return res;
}
// 模块逆元函数
ll modInverse(ll n) {
return power(n, MOD - 2);
}
// 高斯消元求解线性方程组 Ax = b
// A 是 n x n 矩阵, b 是 n 维向量
// 返回解向量 x
vector<ll> gauss_elimination(vector<vector<ll>>& a, vector<ll>& b) {
int n = a.size();
// 构造增广矩阵 [A | b]
vector<vector<ll>> augmented_matrix(n, vector<ll>(n + 1));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
augmented_matrix[i][j] = a[i][j];
}
augmented_matrix[i][n] = b[i];
}
// --- 正向消元 ---
for (int i = 0; i < n; ++i) {
// 找到第 i 列绝对值最大的元素作为主元,以增加数值稳定性
// 在模运算下,我们只需要找到一个非零元素即可
int pivot_row = i;
for (int k = i + 1; k < n; ++k) {
if (augmented_matrix[k][i] != 0) {
pivot_row = k;
break;
}
}
swap(augmented_matrix[i], augmented_matrix[pivot_row]);
// 如果主元是0,说明矩阵奇异,可能无解或有无穷解
// 在本题中,因为 S 是正定的,所以必有唯一解
ll pivot_inv = modInverse(augmented_matrix[i][i]);
// 将主元所在行归一化,使得 a[i][i] = 1
for (int j = i; j <= n; ++j) {
augmented_matrix[i][j] = (augmented_matrix[i][j] * pivot_inv) % MOD;
}
// 将其他行的第 i 列元素消为 0
for (int k = 0; k < n; ++k) {
if (k != i) {
ll factor = augmented_matrix[k][i];
for (int j = i; j <= n; ++j) {
ll term = (factor * augmented_matrix[i][j]) % MOD;
augmented_matrix[k][j] = (augmented_matrix[k][j] - term + MOD) % MOD;
}
}
}
}
// --- 回代得到解 ---
// 经过上面的操作,矩阵 A 部分已经变成了单位矩阵
// 所以增广矩阵的最后一列就是解向量 x
vector<ll> x(n);
for (int i = 0; i < n; ++i) {
x[i] = augmented_matrix[i][n];
}
return x;
}
int main() {
// 加速输入输出,喵~
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
while (cin >> n) {
vector<vector<ll>> A(n, vector<ll>(n));
vector<ll> b(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> A[i][j];
}
}
for (int i = 0; i < n; ++i) {
cin >> b[i];
}
// 1. 构造矩阵 C = A + A^T
vector<vector<ll>> C(n, vector<ll>(n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
C[i][j] = (A[i][j] + A[j][i] + MOD) % MOD;
}
}
// 2. 构造向量 2b
vector<ll> two_b(n);
for (int i = 0; i < n; ++i) {
two_b[i] = (2 * b[i] % MOD + MOD) % MOD;
}
// 3. 求解线性方程组 Cy = 2b, 得到 y
// y 就是我们推导中的 S^{-1}b
vector<ll> y = gauss_elimination(C, two_b);
// 4. 计算最终答案 b^T * y
ll ans = 0;
for (int i = 0; i < n; ++i) {
ans = (ans + (b[i] * y[i]) % MOD + MOD) % MOD;
}
cout << ans << endl;
}
return 0;
}复杂度分析
时间复杂度:
- 构造矩阵 需要 的时间。
- 求解 元线性方程组的高斯消元法,主要计算量在三重循环,复杂度是 。
- 最后计算点积 需要 的时间。
- 所以总的时间复杂度由高斯消元主导,为 ,喵~
空间复杂度:
- 我们需要存储矩阵 , 和增广矩阵,以及向量 和 。其中矩阵占用的空间是主要的,为 。
知识点总结
这道题是数学和算法的美妙结合,涉及到的知识点还不少呢!
- 二次型与对称矩阵: 理解 是关键,它让我们能把问题标准化,用对称矩阵来处理。
- 约束最优化: 问题的本质是在一个约束条件下求函数的极值。
- 拉格朗日乘数法: 解决带等式约束优化问题的强大数学工具,是推导出最终简洁公式的核心。
- 线性方程组求解: 理论推导的最后,问题转化为了求解一个线性方程组 。
- 高斯消元法: 求解线性方程组的标准算法,也是本题在编程实现上的核心。
- 模运算: 别忘了所有计算都要在模 下进行,特别是除法要用乘以逆元的方式来代替。
希望这篇题解能帮助你完全理解这道题目!如果还有不明白的地方,随时可以再来问我哦,喵~ >w<