矩阵特征多项式的求法

就这个东西看了好久才看懂,我在想啥啊

结论:相似矩阵的特征多项式相同

证明:代入定义式即可。

\(A\)\(B\) 相似也就是存在可逆矩阵 \(P\) 使得 \(A=P^{-1}BP\)

只要在对 \(A\) 做初等行变换的时候,同时左乘上它的逆,就可以维持相似性。具体实现背代码

然后就可以得到一个 Hessenberg 矩阵,也就是 \(i\ge j+2\)\(a_{i,j}=0\)。设 \(f_m\) 表示规模为 \(m\) 的顺序主子式的特征多项式,则有

\[f_k=(x-a_{k,k})f_{k-1}-a_{k,k-1}a_{k-1,k}f_{k-2}-a_{k,k-1}a_{k-1,k-2}a_{k-2,k}f_{k-3}-\cdots \]

直接递推求即可。两部分的时间复杂度均为 \(O(n^3)\)

// Gym102984K
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 503, mod = 998244353;
template<typename T>
void read(T &x){
	int ch = getchar(); x = 0;
	for(;ch < '0' || ch > '9';ch = getchar());
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
int n, q, x, a[N][N], p[N][N];
int ksm(int a, int b){
	int res = 1;
	for(;b;b >>= 1, a = (LL)a * a % mod)
		if(b & 1) res = (LL)res * a % mod;
	return res;
} void qmo(int &x){x += x >> 31 & mod;}
int main(){
	read(n); read(q);
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= n;++ j)
			read(a[i][j]);
	for(int i = 1;i < n-1;++ i){
		if(!a[i+1][i])
			for(int j = i+2;j <= n;++ j) if(a[j][i]){
				for(int k = 1;k <= n;++ k) swap(a[i+1][k], a[j][k]);
				for(int k = 1;k <= n;++ k) swap(a[k][i+1], a[k][j]);
				break;
			}
		if(!a[i+1][i]) continue;
		int inv = ksm(a[i+1][i], mod-2);
		for(int j = i+2;j <= n;++ j) if(a[j][i]){
			int tmp = (LL)a[j][i] * inv % mod;
			for(int k = i;k <= n;++ k) qmo(a[j][k] -= (LL)tmp * a[i+1][k] % mod);
			for(int k = 1;k <= n;++ k) a[k][i+1] = (a[k][i+1] + (LL)tmp * a[k][j]) % mod;
		}
	} p[0][0] = 1;
	for(int k = 1;k <= n;++ k){
		for(int i = 1;i <= k;++ i) p[k][i] = p[k-1][i-1];
		for(int i = 0;i <= k;++ i) qmo(p[k][i] -= (LL)a[k][k] * p[k-1][i] % mod);
		int now = 1, tmp;
		for(int i = k-1;i;-- i){
			now = (LL)now * a[i+1][i] % mod;
			tmp = (mod - (LL)now) * a[i][k] % mod;
			for(int j = 0;j <= i;++ j) p[k][j] = (p[k][j] + (LL)tmp * p[i-1][j]) % mod;
		}
	} while(q --){
		read(x); int ans = 0;
		for(int i = n;~i;-- i) ans = ((LL)ans * x + p[n][i]) % mod;
		if(ans && (n & 1)) ans = mod - ans; printf("%d ", ans);
	}
}

SZOJ2651【模板】???

给定两个简单无向图 \(G_1,G_2\) 和正整数 \(p\),求 \(G_1\square G_2\) 的生成树个数模 \(p\) 的值。其中 \(\square\) 表示无向图的笛卡尔积

\(n,m\le 500\)\(10^9+7\le p\le 10^9+181\)\(p\) 为质数。

解法懒得写了,自己看着办(

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector<int> VI;
const int N = 503;
int mod, a[N][N], p[N][N]; char str[N];
int ksm(int a, int b){
	int res = 1;
	for(;b;b >>= 1, a = (LL)a * a % mod)
		if(b & 1) res = (LL)res * a % mod;
	return res;
} void qmo(int &x){x += x >> 31 & mod;}
void work(int n, VI &v){
	memset(a, 0, sizeof a); memset(p, 0, sizeof p);
	for(int i = 1;i < n;++ i){
		scanf("%s", str+1);
		for(int j = i+1;j <= n;++ j)
			if(str[j-i] == '1'){
				++a[i][i]; ++a[j][j];
				a[i][j] = a[j][i] = mod-1;
			}
	}
	for(int i = 1;i < n-1;++ i){
		if(!a[i+1][i])
			for(int j = i+2;j <= n;++ j) if(a[j][i]){
				for(int k = 1;k <= n;++ k) swap(a[i+1][k], a[j][k]);
				for(int k = 1;k <= n;++ k) swap(a[k][i+1], a[k][j]);
				break;
			}
		if(!a[i+1][i]) continue;
		int inv = ksm(a[i+1][i], mod-2);
		for(int j = i+2;j <= n;++ j) if(a[j][i]){
			int tmp = (LL)a[j][i] * inv % mod;
			for(int k = i;k <= n;++ k) qmo(a[j][k] -= (LL)tmp * a[i+1][k] % mod);
			for(int k = 1;k <= n;++ k) a[k][i+1] = (a[k][i+1] + (LL)tmp * a[k][j]) % mod;
		}
	} p[0][0] = 1;
	for(int k = 1;k <= n;++ k){
		for(int i = 1;i <= k;++ i) p[k][i] = p[k-1][i-1];
		for(int i = 0;i <= k;++ i) qmo(p[k][i] -= (LL)a[k][k] * p[k-1][i] % mod);
		int now = 1, tmp;
		for(int i = k-1;i;-- i){
			now = (LL)now * a[i+1][i] % mod;
			tmp = (mod - (LL)now) * a[i][k] % mod;
			for(int j = 0;j <= i;++ j) p[k][j] = (p[k][j] + (LL)tmp * p[i-1][j]) % mod;
		}
	} v.resize(n+1);
	for(int i = 0;i <= n;++ i) v[i] = p[n][i];
}
VI modu(VI a, const VI &b){
	int n = a.size() - 1, m = b.size() - 1, tmp = ksm(b[m], mod-2);
	while(n >= m){
		int x = (LL)tmp * a[n] % mod;
		for(int j = 0;j < m;++ j) qmo(a[n-m+j] -= (LL)x * b[j] % mod);
		a.pop_back(); while(!a.empty() && !a.back()) a.pop_back();
		n = a.size() - 1;
	} return a;
}
int result(const VI &a, const VI &b){
	if(b.empty()) return 0;
	if(b.size() == 1) return ksm(b[0], a.size() - 1);
	VI c = modu(a, b);
	int ans = (LL)ksm(b.back(), a.size() - c.size()) * result(b, c) % mod;
	if(ans && !((a.size() & 1) || (b.size() & 1))) ans = mod - ans;
	return ans;
}
int n, m, ans; VI v1, v2;
int main(){
	scanf("%d%d%d", &n, &m, &mod);
	work(n, v1); work(m, v2); v1.erase(v1.begin());
	for(int i = 1;i <= m;i += 2) if(v2[i]) v2[i] = mod - v2[i];
	if(n <= m){
		ans = (LL)result(v2, v1) * v2[1] % mod;
		if(ans && (n & 1) && (m & 1)) ans = mod - ans;
	} else {
		ans = (LL)result(v1, v2) * v2[1] % mod;
		if(ans && (m & 1)) ans = mod - ans;
	} printf("%d", ans);
}
posted @ 2021-04-16 08:18  mizu164  阅读(1955)  评论(2编辑  收藏  举报