【学习笔记】[ABC323G] Inversion of Tree

news/2024/7/9 6:07:59

前置知识:矩阵树定理,特征多项式

省流:板子缝合题。可以复习一下线性代数的基本知识。

定义 P u > P v P_u>P_v Pu>Pv的边价值为 x x x P u < P v P_u<P_v Pu<Pv的边价值为 1 1 1,那么我们要求一个矩阵 L L L的行列式中 x i x^i xi对应的系数。

暴力做法是 O ( n 4 ) O(n^4) O(n4)的。所以需要一点科技。

考虑特征多项式。对于一个 n × n n\times n n×n的矩阵 A A A,定义它的特征多项式为:

p A ( x ) = det ⁡ ( x I n − A ) p_A(x)=\operatorname{det}(xI_n-A) pA(x)=det(xInA)

其中 I n I_n In是一个 n n n阶的单位矩阵,最后的 p A ( x ) p_A(x) pA(x)是一个 n n n次多项式。

如果一个矩阵次对角线下方的位置全部都是 0 0 0,那么把其称为上海森堡矩阵。

任意 n n n级矩阵的特征多项式都能在 O ( n 3 ) O(n^3) O(n3)的时间复杂度内求出,方法:

1.1 1.1 1.1 利用相似矩阵特征行列式相同的性质将给定矩阵消成上海森堡矩阵

这是因为对于初等可逆矩阵 P P P,有:

det ⁡ ( x I n − A ) = det ⁡ ( x I n − P A P − 1 ) \operatorname{det}(xI_n-A)=\operatorname{det}(xI_n-PAP^{-1}) det(xInA)=det(xInPAP1)

这个东西 好像见过,当时不知道有啥用。。。(其实用处还挺大的,可以加速 矩阵快速幂,但是手算的部分挺难的。。。)

考虑高斯消元的三个操作:

  • 交换两行
  • 将第 i i i行的 k k k倍加到第 j j j行上
  • 将第 i i i行的数乘上 k k k

它们都能写成一个矩阵 P P P。也就是说,每次消元的过程可以看成左乘上矩阵 P P P,而 P − 1 P^{-1} P1不难手算得到,并且右乘上 P − 1 P^{-1} P1等价于是对列进行操作,因此在消元的过程中,当我们对行进行操作时,要同时对列执行其共轭操作。

1.2 1.2 1.2 使用行列式展开定理递推计算它的特征多项式

p i ( x ) p_i(x) pi(x)表示左上角 i × i i\times i i×i的矩阵对应的特征多项式。则递推式 可以一通手算得到

p i ( x ) = x ⋅ p i − 1 ( x ) − ∑ m = 1 i A m , i ( ∏ j = m + 1 i A j , j − 1 ) p m − 1 ( x ) p_i(x)=x\cdot p_{i-1}(x)-\sum_{m=1}^iA_{m,i}(\prod_{j=m+1}^iA_{j,j-1})p_{m-1}(x) pi(x)=xpi1(x)m=1iAm,i(j=m+1iAj,j1)pm1(x)

特别的, p 0 ( x ) = 1 p_0(x)=1 p0(x)=1

对于这道题,考虑将 L L L分解成:

L = A + x B L=A+xB L=A+xB

然后同时对 A , B A,B A,B进行消元操作,即:

L ′ = A ′ + x I L'=A'+xI L=A+xI

最后套用上述做法即可。

注意到第一步过程中如果有一列被消完了那么就将这一列乘上 x x x(等价于将 A A A的这一列搬到 B B B上),如果乘 x x x的次数 > n >n >n就寄了。

因为都是板子,所以建议多看一下代码。

注意行和列都要进行操作。

复杂度 O ( n 3 ) O(n^3) O(n3)

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std;
const int N=505;
const int mod=998244353;
int n,p[N];
ll A[N][N],B[N][N],dp[N][N],res[N];
ll fpow(ll x,ll y=mod-2){
    ll z(1);
    for(;y;y>>=1){
        if(y&1)z=z*x%mod;
        x=x*x%mod;
    }return z;
}
void add(ll &x,ll y){
    x=(x+y)%mod;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;for(int i=0;i<n;i++)cin>>p[i];
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            if(p[i]>p[j]){
                A[i][i]++,A[j][j]++,A[i][j]--,A[j][i]--;
            }
            else{
                B[i][i]++,B[j][j]++,B[i][j]--,B[j][i]--;
            }
        }
    }
    n--;
    int mul=0;
    ll coef=1;
    for(int i=0;i<n;i++){
        for(int j=i;j<n;j++){
            if(A[j][i]!=0){
                swap(A[i],A[j]);
                swap(B[i],B[j]);
                if(i!=j)coef*=-1;
                break;
            }
        }
        while(A[i][i]==0){
            for(int j=0;j<n;j++){
                A[j][i]=B[j][i];
                B[j][i]=0;
            }mul++;
            if(mul>n){
                for(int i=0;i<=n;i++)cout<<0<<"\n";
                return 0;
            }
            for(int j=0;j<i;j++){
                if(A[j][i]!=0){
                    ll x=A[j][i];
                    for(int k=0;k<n;k++){
                        add(A[k][i],-A[k][j]*x);
                        add(B[k][i],-B[k][j]*x);
                    }
                }
            }
            for(int j=i;j<n;j++){
                if(A[j][i]!=0){
                    swap(A[i],A[j]);
                    swap(B[i],B[j]);
                }
                if(i!=j){
                    coef*=-1;
                }
                break;
            }
        }
        ll inv=fpow(A[i][i]);
        coef=coef*A[i][i]%mod;
        for(int j=0;j<n;j++){
            A[i][j]=A[i][j]*inv%mod;
            B[i][j]=B[i][j]*inv%mod;
        }
        for(int j=i+1;j<n;j++){
            if(A[j][i]!=0){
                ll x=A[j][i];
                for(int k=0;k<n;k++){
                    add(A[j][k],-x*A[i][k]);
                    add(B[j][k],-x*B[i][k]);
                }
            }
        }
        for(int j=i+1;j<n;j++){
            if(A[i][j]!=0){
                ll x=A[i][j];
                for(int k=0;k<n;k++){
                    add(A[k][j],-x*A[k][i]);
                    add(B[k][j],-x*B[k][i]);
                }
            }
        }
    }
    for(int i=0;i<n-1;i++){
        int p=-1;
        for(int j=i+1;j<n;j++){
            if(B[j][i]!=0){
                p=j;
                break;
            }
        }
        if(p==-1)continue;
        if(p!=i+1){
            for(int j=0;j<n;j++)swap(B[i+1][j],B[p][j]);
            for(int j=0;j<n;j++)swap(B[j][i+1],B[j][p]);
        }
        for(int j=i+2;j<n;j++){
            if(B[j][i]!=0){
                ll x=B[j][i]*fpow(B[i+1][i])%mod;
                for(int k=0;k<n;k++)add(B[j][k],-B[i+1][k]*x);
                for(int k=0;k<n;k++)add(B[k][i+1],B[k][j]*x);
            }
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            B[i][j]=-B[i][j];
        }
    }
    dp[0][0]=coef;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            dp[i+1][j+1]=dp[i][j];
        }
        ll v=1;
        for(int j=i;j>=0;j--){
            for(int k=0;k<=i+1;k++){
                add(dp[i+1][k],-v*dp[j][k]%mod*B[j][i]);
            }if(j)v=v*B[j][j-1]%mod;
        }
    }
    for(int i=mul;i<=n;i++)res[i-mul]=dp[n][i];
    for(int i=0;i<=n;i++)cout<<(res[i]+mod)%mod<<" ";
}

http://lihuaxi.xjx100.cn/news/1698408.html

相关文章

Jmeter测试关联接口

Jmeter用于接口测试时&#xff0c;后一个接口经常需要用到前一次接口返回的结果&#xff0c;本文主要介绍jmeter通过正则表达式提取器来实现接口关联的方式&#xff0c;可供参考。 一、实例场景&#xff1a; 有如下两个接口&#xff0c;通过正则表达式提取器&#xff0c;将第一…

【数据集资源】大数据资源-数据集下载方法-汇总

大概包含10个领域数据集&#xff1a; 金融 交通 商业 推荐系统 医疗健康 图像数据 视频数据 音频数据 自然语言处理 社会数据 处理后的科研和竞赛数据 1、huggingface的数据下载方式&#xff1a; 1.进入官网数据集列&#xff1a;Hugging Face – The AI community building the…

用3D扫描生成合成数据

合成数据集&#xff08;Synthetic Datasets&#xff09;正在成为计算机视觉模型训练的标准部分。 虽然新工具使合成数据集变得更容易访问&#xff0c;但除了标准机器学习过程之外&#xff0c;许多工具还需要对 3D 建模有基本的了解。 最简单的捷径是从现实世界中获取现有对象并…

分频流水灯

在开发板中&#xff0c;有一个内置的时钟周期&#xff0c;为100MHZ&#xff0c;我们需要使用这样一个时钟信号来设计一个1HZ的流水灯&#xff08;使用8个led灯&#xff09;&#xff0c;也就是一秒钟有一个灯是亮起的&#xff0c;依次从左到右。 另外还有一个低有效的复位使能端…

WuThreat身份安全云-TVD每日漏洞情报-2023-10-13

漏洞名称:libcue <2.2.1 越权访问漏洞 漏洞级别:高危 漏洞编号:CVE-2023-43641,CNNVD-202310-579 相关涉及:系统-alpine_edge-libcue-*-Up to-(excluding)-2.2.1-r0- 漏洞状态:未定义 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-25092 漏洞名称:科大…

1024程序员节日快乐

在这个1024程序员节日&#xff0c;我想和大家分享一个故事&#xff0c;同时展示一些有趣的技术。 曾经有一个年轻的程序员&#xff0c;名叫小明。他热爱编程&#xff0c;对技术充满了好奇心和激情。一天&#xff0c;他遇到了一个挑战&#xff1a;创建一个智能家居系统&#xf…

k8s基础 随笔

写个笔记&#xff0c;后面再完善 部署第一个应用 为什么先实战水平扩缩&#xff1f;因为这个最简单&#xff0c;首先来部署一个喜闻乐见的nginx kubectl create deployment web --imagenginx:1.14 --dry-run -o yaml > web.yaml --dry-run表示试运行&#xff0c;试一下看…

论文阅读 | RAFT: Recurrent All-Pairs Field Transforms for Optical Flow

RAFT: Recurrent All-Pairs Field Transforms for Optical Flow ECCV2020光流任务best paper 论文地址&#xff1a;【here】 代码地址&#xff1a;【here】 介绍 光流是对两张相邻图像中的逐像素运动的一种估计。目前碰到的一些困难包括&#xff1a;物体的快速运动&#xff…