HDU 6446 Tree and Permutation(dfs+思维)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ffgcc/article/details/82431426

解析:
对于树上的一条边,设其两端的点数为 x,y,边长为 L. 对于一个排列,总共会行动 n−1 次,一次行动如果要经过这一条边,那么这次行动的起点和终点一定要在这条边的不同的两端,对应的排列数为 xy(n−2)! . 由于边长为 L, 有 n−1 次行动,还要考虑正反(再乘个 2),所以最终这条边对答案的贡献为2xyL(n−1)! .(大致就是这个结论吧,我也没有太明白。。。)

计算一条边两端的点数用一次 dfs 即可。

#include <bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7f7f7f7f7f
#define mo 1000000007
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N=2e5+10;
ll he[N],sz[N],vis[N],ans=0,n,jc[N];
struct node
{
    ll v,nex;
    ll w;
}ap[N];
ll dfs(int u ){
    sz[u]=1; vis[u]=1;
    for(int i=he[u];i!=-1;i=ap[i].nex){
        int v=ap[i].v;
        if(vis[v]) continue;
        sz[u]+=dfs(v);
        ans=(ans+sz[v]*((ll)n-sz[v])%mo*ap[i].w%mo)%mo;
    }
    return sz[u];
}
int main()
{
    #ifdef local
        freopen("D://rush.txt","r",stdin);
    #endif
    jc[1]=1;
    for(ll i=2;i<N;i++)
    jc[i]=(jc[i-1]*(i))%mo;
    while(scanf("%lld",&n)!=EOF){
        memset(he,-1,sizeof he);memset(vis,0,sizeof vis),ans=0;
        ll x,y,l,cnt=0;
        rep(i,1,n-1){
            scanf("%lld%lld%lld",&x,&y,&l);
            ap[cnt]={y,he[x],l};he[x]=cnt++;
            ap[cnt]={x,he[y],l};he[y]=cnt++;
        }
        dfs(1);
        ans=((ans*jc[n-1]%mo)*2)%mo;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ffgcc/article/details/82431426
今日推荐