2020牛客暑期多校训练营(第一场)D
Quadratic Form
https://ac.nowcoder.com/acm/contest/5666/D
D. Quadratic Form
题目描述
Bobo has a positive-definite matrix and an -dimension vector . He would like to find where , and is maximum.
It can be shown that , which is rational.
Find the value of .
输入描述
The input consists of several test cases terminated by end-of-file.
The first line of each test case contains an integer .
The -th of the following lines contains integers .
The last line contains integers .
, ,.
, for any .
.
The sum of does not exceed .
输出描述
For each test case, print an integer which denotes the result.
示例1
输入
2
1 0
0 1
0 0
2
1 0
0 1
1 1
2
8 4
4 3
1 1
输出
0
2
623902721
分析
将题目转化为约束条件下的最值问题。此处只讨论极值,不讨论边界可能存在的最值。
考虑到约束条件 为不等式约束,可以添加 条件,利用拉格朗日乘数法求解。
首先需要讨论矩阵 的一些性质。由于 ,故 可逆。根据 且 ,得 为实对称矩阵,继而 也为实对称矩阵。又有 ,故 为正定矩阵,继而 也为正定矩阵。上述性质都会在接下来的推导中涉及。
定义:,。 则有约束条件 ,要求最大值的表达式为 或 。
令 ;有 方程组如下。
将 方程组的第一式展开,得到如下方程组。
将上述方程组写成矩阵形式,有 。即 ,等式两边取转置,得 ;,得 。代入约束条件,移项后有 , ;由于 为正定矩阵,故 ;所以约束条件是有效的,即 。根据式 ,可得到最优解为 ;将其带入式 ,有 。
由于 ,代入最优解 ,得 的最大值为 。于是, 最大值为 ;将式 代入,有 。
综上所述,最终答案为 。套用矩阵求逆模板和矩阵乘法公式即可。
代码
/****************************************************************** Copyright: 11D_Beyonder All Rights Reserved Author: 11D_Beyonder Problem ID: 2020牛客暑期多校训练营(第一场) Problem D Date: 7/22/2020 Description: Use lagrange multiplier method Compute the inverse matrix *******************************************************************/ #include<algorithm> #include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int N=202; const ll mod=998244353; ll a[N][N<<1],b[N],c[N]; int n; void inverse(); ll qpow_mod(ll a,int b); int main() { while(~scanf("%d",&n)) { int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%lld",&a[i][j]); a[i][n+j]=0;//初始化 a[i][j]%=mod; } } for(i=1;i<=n;i++) { scanf("%lld",b+i); b[i]%=mod; } inverse(); //========================================= //a[1][1+n]*b[1]+a[2][1+n]*b[2]... //a[2][1+n]*b[1]+a[2][1+n]*b[2]... //... for(j=1;j<=n;j++) { ll res=0; for(i=1;i<=n;i++) { res+=a[i][j+n]*b[i]; res%=mod; } c[j]=res%mod; } //c存b的转置由乘A的结果 //========================================== //计算c右乘B ll ans=0; for(i=1;i<=n;i++) { ans+=b[i]*c[i]; ans%=mod; } //========================================== printf("%lld\n",ans); } return 0; } void inverse()//矩阵求逆模板 { int m=n+n; int i,j,k; for(i=1;i<=n;i++) a[i][i+n]=1; for(i=1;i<=n;i++) { for(j=i;j<=n;j++) { if(a[j][i]) { for(k=1;k<=m;k++) { swap(a[i][k],a[j][k]); } } } ll r=qpow_mod(a[i][i],mod-2); for(j=i;j<=m;j++) a[i][j]=r*a[i][j]%mod; for(j=1;j<=n;j++) { if(i==j) continue; ll rate=a[j][i]*a[i][i]%mod; for(k=i;k<=m;k++) { a[j][k]=a[j][k]-rate*a[i][k]%mod; a[j][k]=(a[j][k]%mod+mod)%mod; } } } } ll qpow_mod(ll a,int b) { ll res=1; while(b) { if(b&1) res=res*a%mod; a=a*a%mod; b>>=1; } return res; }
收集牛客暑期多校训练营的题解