1. 程式人生 > >[洛谷U22156]未曾屆到遊覽(矩陣樹定理)

[洛谷U22156]未曾屆到遊覽(矩陣樹定理)

() cto getc 時間 成了 getchar ret -m 代碼

題目背景


又到了某任*堂開關中學一年一度的自主招生考試的時間了,在考試完後許多家長決定帶著自己的孩子參觀一下這所距千年名校還有890周年的百年學校;

題目描述


這所學校的布局非常奇怪,是一個由N 個點M 條邊構成的無向圖,既然來了肯定要把學校逛完.

家長們的思路也非常清奇,帶孩子走過的邊剛好有n-1 條,並且這n-1 條邊構成了原圖的一棵生成樹。 每條邊上所能看到的風景有兩個固定的價值A 和B ,走了這條邊就只能得到這條邊的A價值,而沒走的邊就只能得到那條邊的B 價值,每個家庭最終看到的總價值的具體算法為所有走過的邊的A 值的乘積*所有沒選的邊的B 值的乘積;

zackzh當年並沒有遊覽學校,所以他想知道所有可能走出的所有生成樹的總價值和MOD1e9+7

輸入輸出格式


輸入格式:

11 行兩個個整數N 與M ,接下來M 每行四個整數U ,V ,A ,B 描述一條邊;

輸出格式:


僅一個整數,即可能走出的所有生成樹的總價值和MOD1e9+7 ;

輸入輸出樣例


輸入樣例#1:
4 7
1 2 1 1
1 3 1 1
1 4 1 1
1 2 1 2
1 3 1 2
1 4 1 2
1 2 1 2

輸出樣例#1:

72

說明


N<=500,M<=200000,A,B<=10;

%10數據滿足 N = 3 M = 12

另有%10數據滿足N = 12 M = 50

另有%10數據滿足N = 500 M = 499

另有%10數據滿足N = 500 M = 1000

另有%10數據滿足 N = 500 M = 100000

剩下%50 數據滿足N = 500 M = 200000

對於%100數據滿足1<=A,B<=10

分析:


就是考察了一下對矩陣樹定理的理解。

在矩陣樹定理樹一棵生成樹的權值求出的其實是它所有邊的乘積,

矩陣樹定理就求出了所有生成樹的權值和。

將邊權設為1就可以求出生成樹個數。

這道題我們可以把生成樹權值設為A / B,設所有邊B乘積為ret

那麽最終答案就是矩陣樹定理求出來的值*ret了。

對於逆元用費馬小定理就好了。

AC代碼:


# include <cstdio>
# include <cstring>
# include <vector>
# include <iostream>
using namespace std;
typedef long long LL;
const LL mod = 1e9 + 7;
void read(int &x)
{
    x = 0;char i = getchar();
    while(!isdigit(i))i = getchar();
    while(isdigit(i))x = x * 10 + i - 0,i = getchar();
}
LL Inc(LL x,LL y){return (x + y + mod) % mod;}
LL Dec(LL x,LL y){return (x - y + mod) % mod;}
LL mul(LL x,LL y){return (x * y % mod + mod) % mod;}
LL a[502][502],ans;int n,m;
LL inv(LL x)
{   LL v = 1;
    for(int i = mod - 2;i;i >>= 1,x = mul(x,x))if(i & 1)v = mul(v,x);
    return v;
}
LL Gauss()
{
    LL ret = 1;
    for(int i = 1;i < n;i++)
    {
        int p = i;
        for(int j = i + 1;j < n;j++)if(a[j][i] > a[p][i])p = j;
        if(p != i)swap(a[p],a[i]),ret = -ret;
        if(!a[i][i])return 0;
        for(int j = i + 1;j < n;j++)
        {
            LL t = a[j][i] * inv(a[i][i]) % mod;
            for(int k = 0;k < n;k++)
            a[j][k] = Dec(a[j][k],mul(t,a[i][k]));
        }
    }
    for(int i = 1;i < n;i++)ret = mul(ret,a[i][i]);
    return ret;
}
int main()
{
    read(n);read(m);int x,y,A,B;LL ret = 1;
    for(int i = 1;i <= m;i++)
    {
        read(x);read(y);read(A);read(B);
        ret = mul(ret,B);
        a[x][y] = Inc(a[x][y],mul(A,inv(B)));
        a[y][x] = Inc(a[y][x],mul(A,inv(B)));
    }
    for(int i = 1;i <= n;i++)
    for(int j = 1;j <= n;j++)
    if(i != j)a[i][i] = Inc(a[i][i],a[i][j]),a[i][j] = mul(-1,a[i][j]);
    printf("%lld\n",mul(ret,Gauss()));
}

[洛谷U22156]未曾屆到遊覽(矩陣樹定理)