【XSY3948】行列式(行列式,树形dp)

题面

行列式

题解

马神说:这可能是本场比赛最简单的一道题。

黑人问号脸.jpg

(这篇题解我很多地方写得很简略或很不严谨,所以如果有些地方看不懂请自己推一推)

考虑构造矩阵 B = ( x ) n × n B=(x)_{n\times n} B=(x)n×n,然后设矩阵 C = A − B C=A-B C=AB

那么矩阵 C C C 满足 C p i , i = b i − x C_{p_i,i}=b_i-x Cpi,i=bix C i , p i = c i − x C_{i,p_i}=c_i-x Ci,pi=cix C i , i = d i − x C_{i,i}=d_i-x Ci,i=dix,且其他地方的值都是 0 0 0

然后我们要求的是 det ⁡ ( A ) = det ⁡ ( B + C ) \det(A)=\det(B+C) det(A)=det(B+C),考虑将其线性展开

不会线性展开的可以利用下面的引理自己展开:

引理:
∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n ⋮ ⋮ ⋮ a i − 1 , 1 a i − 1 , 2 ⋯ a i − 1 , n b 1 + c 1 b 2 + c 2 ⋯ b n + c n a i + 1 , 1 a i + 1 , 2 ⋯ a i + 1 , n ⋮ ⋮ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ = ∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n ⋮ ⋮ ⋮ a i − 1 , 1 a i − 1 , 2 ⋯ a i − 1 , n b 1 b 2 ⋯ b n a i + 1 , 1 a i + 1 , 2 ⋯ a i + 1 , n ⋮ ⋮ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ + ∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n ⋮ ⋮ ⋮ a i − 1 , 1 a i − 1 , 2 ⋯ a i − 1 , n c 1 c 2 ⋯ c n a i + 1 , 1 a i + 1 , 2 ⋯ a i + 1 , n ⋮ ⋮ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ \begin{vmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ \vdots&\vdots&&\vdots\\ a_{i-1,1}&a_{i-1,2}&\cdots&a_{i-1,n}\\ b_1+c_1&b_2+c_2&\cdots&b_n+c_n\\ a_{i+1,1}&a_{i+1,2}&\cdots&a_{i+1,n}\\ \vdots&\vdots&&\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} =\begin{vmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ \vdots&\vdots&&\vdots\\ a_{i-1,1}&a_{i-1,2}&\cdots&a_{i-1,n}\\ b_1&b_2&\cdots&b_n\\ a_{i+1,1}&a_{i+1,2}&\cdots&a_{i+1,n}\\ \vdots&\vdots&&\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} +\begin{vmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ \vdots&\vdots&&\vdots\\ a_{i-1,1}&a_{i-1,2}&\cdots&a_{i-1,n}\\ c_1&c_2&\cdots&c_n\\ a_{i+1,1}&a_{i+1,2}&\cdots&a_{i+1,n}\\ \vdots&\vdots&&\vdots\\ a_{n,1}&a_{n,2}&\cdots&a_{n,n}\\ \end{vmatrix} a1,1ai1,1b1+c1ai+1,1an,1a1,2ai1,2b2+c2ai+1,2an,2a1,nai1,nbn+cnai+1,nan,n=a1,1ai1,1b1ai+1,1an,1a1,2ai1,2b2ai+1,2an,2a1,nai1,nbnai+1,nan,n+a1,1ai1,1c1ai+1,1an,1a1,2ai1,2c2ai+1,2an,2a1,nai1,ncnai+1,nan,n
证明:根据行列式的定义用乘法分配律即可简单证明。

展开后,就能写成每行是 B B B C C C 对应行之一的 2 n 2^n 2n 个矩阵的 det ⁡ \det det 的和。发现这 2 n 2^n 2n 个矩阵中,那些选了大于一行 B B B 的矩阵肯定是没有贡献的,因为 B B B 是个全 x x x 矩阵,而我们又知道 “如果矩阵中有两行成比例,那么其行列式为 0 0 0”。

所以要计算的矩阵中要么选了恰好一行 B B B,要么没有选 B B B

先考虑没有选 B B B 的情况,此时我们要计算的是 det ⁡ ( C ) = ∑ p p ( − 1 ) τ ( p p 1 , p p 2 , ⋯   , p p n ) C 1 , p p 1 C 2 , p p 2 ⋯ C n , p p n \det(C)=\sum\limits_{pp}(-1)^{\tau(pp_1,pp_2,\cdots,pp_n)}C_{1,pp_1}C_{2,pp_2}\cdots C_{n,pp_n} det(C)=pp(1)τ(pp1,pp2,,ppn)C1,pp1C2,pp2Cn,ppn。(这里用 p p pp pp 只是为了和 p p p 区分开来)

此时发现难以直接计算,就有一种比较神奇的做法:

注意到条件 1 ≤ p i < i 1\leq p_i<i 1pi<i,那么如果把 p i p_i pi 当做 i i i 的父亲的话,就会形成一棵树。

由于行列式的定义中,我们每一行都要选一个位置乘起来,不妨设第 i i i 行选了 C i , j C_{i,j} Ci,j(只考虑 C i , j ≠ 0 C_{i,j}\neq 0 Ci,j=0 的情况)。

那么我们不妨把选了 C i , j C_{i,j} Ci,j 看做选了边 ( i , j ) (i,j) (i,j),发现选的边要么在树上,要么是树上某个点的自环。

那么我们不妨给树上的边 ( i , p i ) (i,p_i) (i,pi) 加上边权 c i − x c_i-x cix,边 ( p i , i ) (p_i,i) (pi,i) 加上边权 b i − x b_i-x bix,同时再给树上的每一个点加上一条自环边,其边权为 d i − x d_i-x dix。(不妨仍称这个带有自环的图叫做 “树”)

那这样选了 C i , j C_{i,j} Ci,j 就相当于选了 ( i , j ) (i,j) (i,j) 的边权了。

同时,行列式选完位置后,要保证每一行、每一列都恰好只选了一个位置。

对应到树上,就代表树上选完边并对选的边统计每个点入度出度后(自环 ( u , u ) (u,u) (u,u) u u u 的入度和出度各贡献 1 1 1),每个点的入度和出度恰好为 1 1 1

这个时候会发现一个东西:如果我们选了一条边 ( i , j ) (i,j) (i,j) i ≠ j i\neq j i=j,即不考虑自环),那么我们一定也会选择边 ( j , i ) (j,i) (j,i)。也就是说我们选边时一定是 ( i , p i ) (i,p_i) (i,pi) ( p i , i ) (p_i,i) (pi,i) 捆绑着同时选。

证明比较简单,从树的叶子节点层一直往上推就行了。

那这样就很好讨论了,直接树形dp即可。

具体详见代码。

有一个要注意的地方,就是如何确定每一种选择方案前面的系数( − 1 -1 1 还是 1 1 1)。

假设我们选了 k k k 组捆绑的边,那么系数就是 ( − 1 ) k (-1)^k (1)k

原因(写得你可能看不懂):我们会把 ( i , p i ) (i,p_i) (i,pi) ( p i , i ) (p_i,i) (pi,i) 同时选,而这两个点在矩阵上是关于矩阵斜右向下的对角线对称的。不妨设我们选了一个点 u = ( x , y ) u=(x,y) u=(x,y),那么 u u u 的对称点 u ′ u' u 肯定也被选了。画画图可以得知,如果我们选的两个点 u u u v v v v ≠ u ′ v\neq u' v=u)构成逆序对,那么它们的对称点 u ′ u' u v ′ v' v 也会构成逆序对,此时 − 1 -1 1 就抵消了。所以只有 ( u , u ′ ) (u,u') (u,u) 构成逆序对时才会有贡献,而 ( u , u ′ ) (u,u') (u,u) 的数量就是我们选的捆绑的边的组数。

那么既然系数和选的边的组数有关,那么系数就可以在树形dp时顺便处理了。

而对于求选了恰好一行 B B B 的矩阵的行列式,假设选的是第 i i i 行,我们就把原来树上所有 i i i 的出边先去掉,再向所有点都连一条边权为 x x x 的边,然后也是要满足每个点的入度和出度恰好为 1 1 1,要求不同选边方案的贡献的总和。

这个我们同样也可以用树形dp来搞定。

至于这时如何确定每一种选择方案前面的系数( − 1 -1 1 还是 1 1 1),我们先称选的那条边权为 x x x 的边所在的环为 “ X X X 环”。

不妨设我们在 X X X 环上选了边 ( a 1 , a 2 ) , ( a 2 , a 3 ) , ⋯   , ( a k − 1 , a k ) , ( a k , a 1 ) (a_1,a_2),(a_2,a_3),\cdots,(a_{k-1},a_k),(a_k,a_1) (a1,a2),(a2,a3),,(ak1,ak),(ak,a1),在 X X X 环外选了边 ( b 1 , c 1 ) , ( c 1 , b 1 ) , ( b 2 , c 2 ) , ( c 2 , b 2 ) , ⋯   , ( b l , c l ) , ( c l , b l ) (b_1,c_1),(c_1,b_1),(b_2,c_2),(c_2,b_2),\cdots,(b_l,c_l),(c_l,b_l) (b1,c1),(c1,b1),(b2,c2),(c2,b2),,(bl,cl),(cl,bl),那么我们要求的系数即为:
( − 1 ) τ ( b 1 , c 1 , b 2 , c 2 , ⋯   , b l , c l , a 1 , a 2 , ⋯   , a k − 1 , a k ) + τ ( c 1 , b 1 , c 2 , b 2 , ⋯   , c l , b l , a 2 , a 3 , ⋯   , a k , a 1 ) (-1)^{\tau(b_1,c_1,b_2,c_2,\cdots,b_l,c_l,a_1,a_2,\cdots,a_{k-1},a_k)+\tau(c_1,b_1,c_2,b_2,\cdots,c_l,b_l,a_2,a_3,\cdots,a_k,a_1)} (1)τ(b1,c1,b2,c2,,bl,cl,a1,a2,,ak1,ak)+τ(c1,b1,c2,b2,,cl,bl,a2,a3,,ak,a1)
我们只需讨论 τ ( b 1 , c 1 , b 2 , c 2 , ⋯   , b l , c l , a 1 , a 2 , ⋯   , a k − 1 , a k ) + τ ( c 1 , b 1 , c 2 , b 2 , ⋯   , c l , b l , a 2 , a 3 , ⋯   , a k , a 1 ) \tau(b_1,c_1,b_2,c_2,\cdots,b_l,c_l,a_1,a_2,\cdots,a_{k-1},a_k)+\tau(c_1,b_1,c_2,b_2,\cdots,c_l,b_l,a_2,a_3,\cdots,a_k,a_1) τ(b1,c1,b2,c2,,bl,cl,a1,a2,,ak1,ak)+τ(c1,b1,c2,b2,,cl,bl,a2,a3,,ak,a1) 的奇偶性即可。

记序列 p 1 = ( b 1 , c 1 , b 2 , c 2 , ⋯   , b l , c l , a 1 , a 2 , ⋯   , a k − 1 , a k ) p_1=(b_1,c_1,b_2,c_2,\cdots,b_l,c_l,a_1,a_2,\cdots,a_{k-1},a_k) p1=(b1,c1,b2,c2,,bl,cl,a1,a2,,ak1,ak),将其分为左半部分 p l 1 = ( b 1 , c 1 , b 2 , c 2 , ⋯   , b l , c l ) pl_1=(b_1,c_1,b_2,c_2,\cdots,b_l,c_l) pl1=(b1,c1,b2,c2,,bl,cl) 和右半部分 p r 1 = ( a 1 , a 2 , ⋯   , a k − 1 , a k ) pr_1=(a_1,a_2,\cdots,a_{k-1},a_k) pr1=(a1,a2,,ak1,ak)

同理得到 p 2 = ( c 1 , b 1 , c 2 , b 2 , ⋯   , c l , b l , a 2 , a 3 , ⋯   , a k , a 1 ) p_2=(c_1,b_1,c_2,b_2,\cdots,c_l,b_l,a_2,a_3,\cdots,a_k,a_1) p2=(c1,b1,c2,b2,,cl,bl,a2,a3,,ak,a1) p l 2 = ( c 1 , b 1 , c 2 , b 2 , ⋯   , c l , b l ) pl_2=(c_1,b_1,c_2,b_2,\cdots,c_l,b_l) pl2=(c1,b1,c2,b2,,cl,bl) p r 2 = ( a 2 , a 3 , ⋯   , a k , a 1 ) pr_2=(a_2,a_3,\cdots,a_k,a_1) pr2=(a2,a3,,ak,a1)

考虑 p l 1 pl_1 pl1 中的数 p 1 , i p_{1,i} p1,i p r 1 pr_1 pr1 中的数 p 1 , j p_{1,j} p1,j 产生的逆序对集合 P 1 = { ( p 1 , i , p 1 , j ) } P_1=\{(p_{1,i},p_{1,j})\} P1={(p1,i,p1,j)},以及 p l 2 pl_2 pl2 中的数 p 2 , i p_{2,i} p2,i p r 2 pr_2 pr2 中的数 p 2 , j p_{2,j} p2,j 产生的逆序对集合 P 2 = { ( p 2 , i , p 2 , j ) } P_2=\{(p_{2,i},p_{2,j})\} P2={(p2,i,p2,j)},不难发现这两个集合是完全相同的。因为 p l 1 pl_1 pl1 中的数的集合和 p l 2 pl_2 pl2 中的数的集合是完全相同的,而 p r 1 pr_1 pr1 中的数的集合和 p r 2 pr_2 pr2 中的数的集合也是完全相同的。

所以 P 1 P_1 P1 P 2 P_2 P2 对逆序对个数的贡献会因为只考虑奇偶性而被抵消掉。

所以我们只需要考虑 p l 1 , p r 1 , p l 2 , p r 2 pl_1,pr_1,pl_2,pr_2 pl1,pr1,pl2,pr2 它们各自的逆序对个数之和的奇偶性即可。

p l 1 pl_1 pl1 p l 2 pl_2 pl2 的贡献直接按我们第一种情况(即求 det ⁡ ( C ) \det(C) det(C) 的情况)处理即可,而对于求 ( τ ( p r 1 ) + τ ( p r 2 ) )   m o d   2 \big(\tau(pr_1)+\tau(pr_2)\big) \bmod 2 (τ(pr1)+τ(pr2))mod2
τ ( p r 1 ) + τ ( p r 2 ) = τ ( a 1 , a 2 , ⋯   , a k − 1 , a k ) + τ ( a 2 , a 3 , ⋯   , a k , a 1 ) = a 1   和   ( a 2 , ⋯   , a k − 1 , a k )   的逆序对个数 + ( a 2 , ⋯   , a k − 1 , a k )   和   a 1   的逆序对个数 + 2 τ ( a 2 , ⋯   , a k − 1 , a k ) ≡ a 1   和   ( a 2 , ⋯   , a k − 1 , a k )   的逆序对个数 + ( a 2 , ⋯   , a k − 1 , a k )   和   a 1   的逆序对个数 ≡ k − 1 ( m o d 2 ) \begin{aligned} \tau(pr_1)+\tau(pr_2) =&\tau(a_1,a_2,\cdots,a_{k-1},a_k)+\tau(a_2,a_3,\cdots,a_k,a_1)\\ =&\text{$a_1\,$和$\,(a_2,\cdots,a_{k-1},a_k)\,$的逆序对个数}+\text{$(a_2,\cdots,a_{k-1},a_k)\,$和$\,a_1\,$的逆序对个数}+\\ &2\tau(a_2,\cdots,a_{k-1},a_k)\\ \equiv&\text{$a_1\,$和$\,(a_2,\cdots,a_{k-1},a_k)\,$的逆序对个数}+\text{$(a_2,\cdots,a_{k-1},a_k)\,$和$\,a_1\,$的逆序对个数}\\ \equiv&k-1\pmod 2 \end{aligned} τ(pr1)+τ(pr2)==τ(a1,a2,,ak1,ak)+τ(a2,a3,,ak,a1)a1(a2,,ak1,ak)的逆序对个数+(a2,,ak1,ak)a1的逆序对个数+2τ(a2,,ak1,ak)a1(a2,,ak1,ak)的逆序对个数+(a2,,ak1,ak)a1的逆序对个数k1(mod2)
那么也可以在树形dp时顺便处理了。

代码如下:

#include<bits/stdc++.h>

#define N 1000010

using namespace std;

namespace modular
{
	const int mod=1000000007;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int n,x,d[N];
int cnt,head[N],nxt[N<<1],to[N<<1],bb[N<<1],cc[N<<1];
int f[N][6],g[6];
//不妨设我们选的边权长度为x的边为(u,v),那么下面的“X路径”是指树上的路径v->u(即X环去掉(u,v)的那部分)
//f[u][0]:已处理完u子树内的边,u子树内无X路径,u需要选与父亲相连的那条双向边(即两条单向边都选上)
//f[u][1]:已处理完u子树内的边,u子树内无X路径,u不能选与父亲相连的那条双向边
//f[u][2]:已处理完u子树内的边,u子树包含完整的X路径,u需要选与父亲相连的那条双向边
//f[u][3]:已处理完u子树内的边,u子树包含完整的X路径,u不能选与父亲相连的那条双向边
//f[u][4]:已处理完u子树内的边,X路径的终点在u子树内,起点在u子树外
//f[u][5]:已处理完u子树内的边,X路径的起点在u子树内,终点在u子树外

void adde(int u,int v,int b,int c)
{
	to[++cnt]=v;
	bb[cnt]=b,cc[cnt]=c;
	nxt[cnt]=head[u];
	head[u]=cnt;
}

void dfs(int u)
{
	f[u][0]=f[u][4]=f[u][5]=1;
	f[u][1]=d[u];
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i],b=bb[i],c=cc[i];
		dfs(v);
		memset(g,0,sizeof(g));
		g[0]=mul(f[u][0],f[v][1]);
		g[1]=mul(f[u][1],f[v][1]);
		g[1]=add(g[1],mul(f[u][0],dec(0,mul(mul(b,c),f[v][0]))));
		g[2]=mul(f[u][2],f[v][1]);
		g[2]=add(g[2],mul(f[u][0],f[v][3]));
		g[3]=mul(f[u][3],f[v][1]);
		g[3]=add(g[3],mul(f[u][1],f[v][3]));
		g[3]=add(g[3],mul(f[u][0],dec(0,mul(mul(b,c),f[v][2]))));
		g[3]=add(g[3],mul(f[u][2],dec(0,mul(mul(b,c),f[v][0]))));
		g[3]=add(g[3],mul(f[u][5],dec(0,mul(mul(x,b),f[v][4]))));
		g[3]=add(g[3],mul(f[u][4],dec(0,mul(mul(x,c),f[v][5]))));
		g[4]=mul(f[u][4],f[v][1]);
		g[4]=add(g[4],mul(f[u][0],dec(0,mul(b,f[v][4]))));
		g[5]=mul(f[u][5],f[v][1]);
		g[5]=add(g[5],mul(f[u][0],dec(0,mul(c,f[v][5]))));
		memcpy(f[u],g,sizeof(f[u]));
	}
	f[u][3]=add(f[u][3],mul(x,f[u][0]));//X路径是自环
}

int main()
{
	n=read(),x=read();
	for(int i=1;i<=n;i++) d[i]=dec(read(),x);
	for(int i=2;i<=n;i++)
	{
		int p=read(),b=dec(read(),x),c=dec(read(),x);
		adde(p,i,b,c);
	}
	dfs(1);
	printf("%d\n",add(f[1][1],f[1][3]));
	return 0;
}
/*
3 1 
1 1 1
1 2 3
1 4 5
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,你遇到的问题是在发送HTTP POST请求时收到了403 Forbidden的错误。这个错误通常表示你没有权限访问所请求的资源。 要解决这个问题,你可以采取以下步骤: 1. 首先,确保你的请求URL正确,并且你有权限访问该URL。你可以尝试在浏览器中直接访问该URL,看看是否能够成功访问。 2. 如果你确定URL是正确的,并且你有权限访问,那么可能是你的请求中缺少了必要的身份验证信息。你可以检查你的请求头中是否包含了正确的身份验证信息,比如Token或用户名密码。 3. 另外,你还可以检查服务器端的配置,确保你的请求被正确地处理和授权。你可以查看服务器的日志,以了解更多关于403错误的详细信息。 综上所述,当你收到403 Forbidden错误时,你应该首先检查URL和权限,然后确保请求中包含了正确的身份验证信息。如果问题仍然存在,你可以进一步检查服务器端的配置和日志,以找出问题的根本原因。 #### 引用[.reference_title] - *1* [kubeadm init报错10248...(The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ failed)](https://blog.csdn.net/weixin_45969972/article/details/123529966)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST)](https://blog.csdn.net/xsy29000/article/details/103181267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值