1. 程式人生 > >HDU-6446Tree and Permutation

HDU-6446Tree and Permutation

onclick eight -s div eve i++ amp 技術 long

Tree and Permutation

題意:

給一棵N個點的樹,對應於一個長為N的全排列,對於排列的每個相鄰數字a和b,他們的貢獻是對應樹上頂點a和b的路徑長,求所有排列的貢獻和。

思路:對每條邊單獨計算貢獻,一條邊B將樹分成兩側,假設其中一側大小為M,則另一側大小為
N- M.
在N!條路線中每條都分為N - 1段,對每段單獨計算貢獻,例如某一-段從X到Y,則該段經過
E當且僅當X與Y在E的兩側,對應的排列數為2M(N一M)(N一2)!.共有N - 1段,假設E的長度為L,則E的貢獻為2LM(N一M)(N - 1)!.

那麽如何求樹上各個點的距離和呢,樹形dp?

可以參考這個博客:https://www.cnblogs.com/shuaihui520/p/9537214.html ;

ac代碼

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const int mod = 1e9+7;
ll sum[maxn], n;
ll dp[maxn];
ll b[maxn];
struct Edge
{
    int v, w;
};
vector<Edge> tree[maxn];
void dfs(int cur, int father)
{
    sum[cur] = 1;
    
for(int i = 0; i < tree[cur].size(); i++) { int son = tree[cur][i].v; ll len = tree[cur][i].w; if(father == son) continue; dfs(son, cur); sum[cur] =(sum[cur]+sum[son])%mod;//子節點的個數 dp[cur]= ((dp[cur]+dp[son])%mod + (n-sum[son])*sum[son]%mod * len%mod)%mod; } }
int main() { // freopen("in.txt","r",stdin); int u, v; ll w; b[1]=1; for(int i=2;i<=100000;i++)b[i]=i*b[i-1]%mod; while(~scanf("%d",&n)) { memset(sum, 0, sizeof(sum)); memset(dp, 0, sizeof(dp)); for(int i = 0; i < n-1; i++) { scanf("%d%d%lld", &u, &v, &w); Edge t1, t2; t1.v = v; t1.w = w; t2.v = u; t2.w = w; tree[u].push_back(t1); tree[v].push_back(t2); } dfs(1,0); //ll f=1; ll ans=dp[1]*b[n-1]%mod; ans=ans*2%mod; printf("%lld\n",ans); for(int i = 1; i <= n; i++) tree[i].clear(); } return 0; }
View Code

HDU-6446Tree and Permutation