\(\mathcal{Description}\)

  Link.

  给定 \(x,\{d_i\}_{i=1}^n,\{p_i\}_{i=2}^n,\{b_i\}_{i=2}^n,\{c_i\}_{i=2}^n\),构造矩阵 \(A=(a_{ij})_{n\times n}\):

\[a_{ij}=\begin{cases}
b_j,&i=p_j\\
c_i,&j=p_i\\
d_i,&i=j\\
x,&\text{otherwise}
\end{cases}.
\]

求 \(\det A\)。

  \(n\le10^6\),\(p_i\in[1,i)\)。

\(\mathcal{Solution}\)

\(p_i\in[1,i),~i=2,3,\dots,n\)。

  这是什么?这是树!

  在这样意识流的思考下,我们选择将 \(A\) 看做邻接矩阵,那么自然地区分出了三类边:

  • 树边,以 \(1\) 位根,父亲到儿子的边权是 \(b\),儿子到父亲的边权是 \(c\);
  • 自环,边权为 \(d\);
  • 非树边,边权为 \(x\)。

  矩阵中有大面积的常数 \(x\),利用 trick,从行列式的定义式的角度抵消大量贡献。具体地,令 \(X=(x)_{n\times n},Y=A-X\),则

\[\begin{aligned}
\det A&=\det (X+Y)\\
&=\sum_{\sigma}(-1)^{\tau(\sigma)}\prod_{i=1}^n(x+y_{i\sigma_i}).
\end{aligned}
\]

此番强行构造出二项式相乘的形式,若累乘式中至少 \(2\) 项选择了 \(x\),不妨设选择 \(x\) 的位置为 \(\{q_1,q_2,\cdots,q_k\}~(k>1)\),那么于 \(\sigma\) 中交换 \(\sigma_{q_1}\) 和 \(\sigma_{q_2}\) 的位置得到 \(\sigma'\),在新的累乘式中同样选择 \(\{q_1,q_2,\cdots,q_k\}\) 为 \(x\),而 \((-1)^{\tau(\sigma)+\tau(\sigma')}=0\),并且 \(\sigma\) 与 \(\sigma'\) 两两对应抵消,所以这样的方案是没有贡献的!

  回到图上,考虑 \(\prod_{i=1}^n a_{i\sigma_i}\) 的组合意义:每个结点 \(i\) 选择邻接边 \(\lang i,\sigma_i\rang\),得到边权的乘积。所选的边显然构成若干简单环,而在排除至多出现一次的含有非树边 \(x\) 的环,其余环必然是自环或树边二元环!(注意含非树边的环亦可为这两种情况。)

  进一步,尝试树上 DP 求解这一形象问题。在计算逆序对 \(\tau(\sigma)\) 时,利用结论

设 \(\sigma\) 轮换分解后得到偶排列的的个数为 \(c\),则 \((-1)^c=(-1)^{\tau(\sigma)}\)。(易证。)

可以将 \((-1)\) 的贡献直接乘到状态的值中。具体来说,对于 \(u\) 点,状态应有:

  • 子树内无 \(x\) 环;\(u\) 在子树内的环中;
  • 子树内有 \(x\) 环;\(u\) 在子树内的环中;
  • 子树内无 \(x\) 环;\(u\) 不在子树内的环中且不在 \(x\) 环中;
  • 子树内有 \(x\) 环;\(u\) 不在子树内的环中且不在 \(x\) 环中;
  • 子树内无 \(x\) 环;\(u\) 在顶点高于 \(u\) 的 \(x\) 环中,且选择向上的树边;
  • 子树内无 \(x\) 环;\(u\) 在顶点高于 \(u\) 的 \(x\) 环中,且选择向下的树边。

六种情况,分别写出转移式子即可。(当然也可以用多维状态来让思路更清晰。)

  最终,复杂度 \(\mathcal O(n)\)。

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <cstdio>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) inline int rint() {
int x = 0, f = 1, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar() ) x = x * 10 + ( s ^ '0' );
return x * f;
} template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
} const int MAXN = 1e6, MOD = 1e9 + 7;
int n, ecnt, head[MAXN + 5], x, b[MAXN + 5], c[MAXN + 5], d[MAXN + 5];
int f[MAXN + 5][6];
struct Edge { int to, nxt; } graph[MAXN * 2 + 5]; inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); } inline void link( const int s, const int t ) {
graph[++ecnt] = { t, head[s] }, head[s] = ecnt;
} inline void solve( const int u ) {
f[u][0] = f[u][4] = f[u][5] = 1, f[u][1] = d[u];
for ( int i = head[u], v; i; i = graph[i].nxt ) {
solve( v = graph[i].to );
static int tmp[6];
tmp[0] = mul( f[u][0], f[v][1] ); tmp[1] = mul( f[u][1], f[v][1] );
subeq( tmp[1], mul( mul( f[u][0], f[v][0] ), mul( b[v], c[v] ) ) ); tmp[2] = mul( f[u][2], f[v][1] );
addeq( tmp[2], mul( f[u][0], f[v][3] ) ); tmp[3] = mul( f[u][3], f[v][1] );
addeq( tmp[3], mul( f[u][1], f[v][3] ) );
subeq( tmp[3], mul( mul( f[u][0], f[v][2] ), mul( b[v], c[v] ) ) );
subeq( tmp[3], mul( mul( f[u][2], f[v][0] ), mul( b[v], c[v] ) ) );
subeq( tmp[3], mul( mul( f[u][4], f[v][5] ), mul( x, c[v] ) ) );
subeq( tmp[3], mul( mul( f[u][5], f[v][4] ), mul( x, b[v] ) ) ); tmp[4] = mul( f[u][4], f[v][1] );
subeq( tmp[4], mul( mul( f[u][0], f[v][4] ), b[v] ) ); tmp[5] = mul( f[u][5], f[v][1] );
subeq( tmp[5], mul( mul( f[u][0], f[v][5] ), c[v] ) ); rep ( j, 0, 5 ) f[u][j] = tmp[j];
}
addeq( f[u][3], mul( x, f[u][0] ) );
} int main() {
freopen( "B.in", "r", stdin );
freopen( "B.out", "w", stdout ); n = rint(), x = rint();
rep ( i, 1, n ) d[i] = sub( rint(), x );
rep ( i, 2, n ) {
link( rint(), i ), b[i] = sub( rint(), x ), c[i] = sub( rint(), x );
} solve( 1 ); wint( add( f[1][1], f[1][3] ) ), putchar( '\n' );
return 0;
}

Solution -「多校联训」行列式的更多相关文章

  1. Solution -「多校联训」排水系统

    \(\mathcal{Description}\)   Link.   在 NOIP 2020 A 的基础上,每条边赋权值 \(a_i\),随机恰好一条边断掉,第 \(i\) 条段的概率正比于 \(a ...

  2. Solution -「多校联训」I Love Random

    \(\mathcal{Description}\)   给定排列 \(\{p_n\}\),可以在其上进行若干次操作,每次选取 \([l,r]\),把其中所有元素变为原区间最小值,求能够得到的所有不同序 ...

  3. Solution -「多校联训」签到题

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\ ...

  4. Solution -「多校联训」朝鲜时蔬

    \(\mathcal{Description}\)   Link.   破案了,朝鲜时蔬 = 超现实树!(指写得像那什么一样的题面.   对于整数集 \(X\),定义其 好子集 为满足 \(Y\sub ...

  5. Solution -「多校联训」消失的运算符

    \(\mathcal{Description}\)   Link.   给定长度为 \(n\) 的合法表达式序列 \(s\),其中数字仅有一位正数,运算符仅有 - 作为占位.求将其中恰好 \(k\) ...

  6. Solution -「多校联训」假人

    \(\mathcal{Description}\)   Link.   一种物品有 长度 和 权值 两种属性,现给定 \(n\) 组物品,第 \(i\) 组有 \(k_i\) 个,分别为 \((1,a ...

  7. Solution -「多校联训」古老的序列问题

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答 \[\sum_{[l,r]\su ...

  8. Solution -「多校联训」Sample

    \(\mathcal{Description}\)   Link   (稍作简化:)对于变量 \(p_{1..n}\),满足 \(p_i\in[0,1],~\sum p_i=1\) 时,求 \(\ma ...

  9. Solution -「多校联训」光影交错

    \(\mathcal{Description}\)   Link.   一个游戏包含若干次卡牌抽取,每次以 \(p_l\) 的概率得到 \(+1\),\(p_d\) 的概率得到 \(-1\),否则得到 ...

随机推荐

  1. Hive的基本概念和常用命令

    原文链接: https://www.toutiao.com/i6766571623727235595/?group_id=6766571623727235595 一.概念: 1.结构化和非结构化数据 ...

  2. TestNG中 ITestListener 的使用

    1.关于testng中ITestListener 的相关介绍文档,请参考: http://javadox.com/org.testng/testng/6.8.7/org/testng/ITestLis ...

  3. Java反射详解:入门+使用+原理+应用场景

    反射非常强大和有用,现在市面上绝大部分框架(spring.mybatis.rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用. 所以,在你Java进阶的道路上,你需要掌握好 ...

  4. linux开放端口关闭防火墙

    linux开放端口关闭防火墙 systemctl status firewalld查看当前防火墙状态. 开启防火墙      systemctl start firewalld开放指定端口       ...

  5. 515. Find Largest Value in Each Tree Row

    You need to find the largest value in each row of a binary tree. Example: Input: 1 / \ 3 2 / \ \ 5 3 ...

  6. Shell 脚本循环遍历日志文件中的值进行求和并计算平均值,最大值和最小值

    本文为博主原创,转载请注明出处: 最近在进行压测,为了观察并定位服务性能的瓶颈,所以在代码中很多地方加了执行耗时的日志,但这种方式只能观察,却在压测的时候,不太能准确的把握代码中某些方法的性能,所以想 ...

  7. C++普通成员函数的调用形式

    #include<iostream> using namespace std; class A { public: int data; void foo(int x) { data = x ...

  8. C++类对象大小问题(一)

    先看如下代码: #include<iostream> using namespace std; class Base1 { public: }; class Base2 { public: ...

  9. kubernetes集群各模块功能描述

    Master节点: Master节点上面主要由四个模块组成,APIServer,schedule,controller-manager,etcd APIServer: APIServer负责对外提供R ...

  10. python32day

    内容回顾 操作系统的历史 多道操作系统 分时操作系统 实时操作系统 进程 线程 并行和并发 同步和异步 阻塞和非阻塞 今日内容 进程的三状态图 进程的调度算法 给所有进程分配资源或者分配CPU使用权的 ...