1. 程式人生 > >HDU 6446 Tree and Permutation (樹形DP經典)

HDU 6446 Tree and Permutation (樹形DP經典)

Tree and Permutation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 541    Accepted Submission(s): 182


 

Problem Description

There are N vertices connected by N−1 edges, each edge has its own length.
The set { 1,2,3,…,N } contains a total of N! unique permutations, let’s say the i -th permutation is Pi and Pi,j is its j -th number.
For the i -th permutation, it can be a traverse sequence of the tree with N vertices, which means we can go from the Pi,1 -th vertex to the Pi,2 -th vertex by the shortest path, then go to the Pi,3 -th vertex ( also by the shortest path ) , and so on. Finally we’ll reach the Pi,N -th vertex, let’s define the total distance of this route as D(Pi) , so please calculate the sum of D(Pi) for all N! permutations.

 

Input

There are 10 test cases at most.
The first line of each test case contains one integer N ( 1≤N≤105 ) .
For the next N−1 lines, each line contains three integer X , Y and L , which means there is an edge between X -th vertex and Y -th of length L ( 1≤X,Y≤N,1≤L≤109 ) .

 

Output

For each test case, print the answer module 109+7 in one line.

 

Sample Input

3 1 2 1 2 3 1 3 1 2 1 1 3 2

 

Sample Output

16 24

 

Source

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  

6447 6446 6445 6444 6443 

#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)

#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ll long long
const int  maxn =1e5+5;
const int mod=1e9+7;

ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
ll powmod(ll x,ll y){ll t;for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod;return t;}

/*
題目大意:題目敘述上饒了點彎子,
對於一個排列的權重,代表從a1走到a2,a2走到a3,,,這樣走下去的權重和,就是一個排列的權重,
然後求全排列的權重和。。

數學轉換下即可:對於任意的xy,其在全排列中相鄰的組合數是(n-1)!*2。

這樣題目意思就明瞭了,求一棵樹中任意兩點距離和,邊上有權重。

貢獻思維,看每條邊對答案的貢獻。
一條邊被n1*n2次走過,n1,n2分別為邊兩邊的子樹的節點數。

樹形DP去解析,有三個狀態,子節點數,子節點到根節點距離和,子樹中任意兩點距離和。

三個狀態具體如何轉移詳見程式碼,狀態和順序絕對不能錯。

(我這個好像寫煩了,,其實就是簡單的對每個邊求其貢獻即可,分開的兩顆子樹節點乘積*權重。。。)
*/

struct node///鏈式前向星板子
{
    int nxt;
    int e;
    ll w;
    node(int x=0,int y=0,ll z=0)
    {
        e=x;
        nxt=y;
        w=z;
    }
};

node edge[maxn<<1];
int head[maxn],tot=0;
void init(){memset(head,-1,sizeof(head));tot=0;}
void add(int a,int b,ll c){edge[tot]=node(b,head[a],c);head[a]=tot++;}

ll n,dp[maxn][3];///0代表子樹的節點數,1代表子樹中所有點到根節點的路徑之和,2代表子樹中任意點對距離和。
void dfs(int u,int p)
{
    if(head[u]==-1) {dp[u][0]=1;return ;}
    for(int i=head[u];~i;i=edge[i].nxt)
    {
        int v=edge[i].e;
        if(v==p) continue;
        dfs(v,u);
        (dp[u][2]+=dp[v][2]+dp[v][1]*dp[u][0]%mod+dp[v][0]*dp[u][1]%mod+dp[u][0]*dp[v][0]%mod*edge[i].w%mod)%=mod;///又是一個線性的動態規劃
        (dp[u][1]+=dp[v][1]%mod+dp[v][0]*edge[i].w%mod)%=mod;
        (dp[u][0]+=dp[v][0])%=mod;///子樹的頂點數
    }
    dp[u][0]++;
    (dp[u][2]+=dp[u][1])%=mod;///
}

int x,y;
ll fac[maxn],z;

int main()
{
    fac[0]=1;for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%mod;

    while(~scanf("%lld",&n))
    {
        init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        memset(dp,0,sizeof(dp));
        dfs(1,-1);
        ll ans=dp[1][2]*fac[n-1]%mod*2%mod;
        printf("%lld\n",ans);
    }
    return 0;
}
/*
4
1 3 1
1 2 1
1 4 1


*/