1. 程式人生 > 其它 >Solution -「多校聯訓」行列式

Solution -「多校聯訓」行列式

\(\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;
}