HDU 6446 Tree and Permutation (樹形DP經典)
Tree and PermutationTime 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. Input There are 10 test cases at most. 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: |
#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
*/