就这个东西看了好久才看懂,我在想啥啊
结论:相似矩阵的特征多项式相同。
证明:代入定义式即可。
(A) 与 (B) 相似也就是存在可逆矩阵 (P) 使得 (A=P^{-1}BP)。
只要在对 (A) 做初等行变换的时候,同时左乘上它的逆,就可以维持相似性。具体实现背代码
然后就可以得到一个 Hessenberg 矩阵,也就是 (ige 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_1square G_2) 的生成树个数模 (p) 的值。其中 (square) 表示无向图的笛卡尔积。
(n,mle 500),(10^9+7le ple 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);
}