hdu 4661 Message Passing(木DP&组合数学)

hdu 4661 Message Passing(木DP&组合数学)

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

Message Passing

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1187    Accepted Submission(s): 423

Problem Description
There are n people numbered from 1 to n. Each people have a unique message. Some pairs of people can send messages directly to each other, and this relationship forms a structure of a tree. In one turn, exactly one person sends all messages s/he currently has to another person. What is the minimum number of turns needed so that everyone has all the messages?

This is not your task. Your task is: count the number of ways that minimizes the number of turns. Two ways are different if there exists some k such that in the k-th turn, the sender or receiver is different in the two ways.

 

Input
First line, number of test cases, T.

Following are T test cases.

For each test case, the first line is number of people, n. Following are n-1 lines. Each line contains two numbers.

Sum of all n <= 1000000.

 

Output
T lines, each line is answer to the corresponding test case. Since the answers may be very large, you should output them modulo 10
9+7.
 

Sample Input
   
   
2 2 1 2 3 1 2 2 3

 

Sample Output
   
   
2 6

 

Source

Recommend
 题意:
n个人,构成树形关系。每一个人有一条独一无二的信息。每一个人能够将自己的信息通过树边。共享给与他相邻的人,共享之后。被共享的人拥有他原有的信息和共享的来的信息。

每次共享为一次操作。问每一个人都拥有全部人的信息最小要的次数的共享方法有多少种。

思路:
easy的出。最短的时间内。当然是每一个节点将自己的信息想外传出去一次。而且接受一次信息,也就是树边的2倍2*(n-1)。
然后能够证明。在最短时间内,全部的传递方式都有一个“信息转换点”——其它节点的信息首先传递到此节点,然后信息再从这个节点向其它节点传递。

事实上我们要求的就是拓扑序有多少种。定义dp[u]表示u节点下面。传到u节点的拓扑序有多少种,cnt[u]表示u有多少个子孙节点,f[i] = i!(i的阶乘)。c[i][j]表示组合数。

如果它有v1,v2,v3个节点。它们的拓扑序分别有dp[v1],dp[v2],dp[v3]这么多种。

那么dp[u] = c[cnt[u]-1][cnt[v1]] * c[cnt[u]-1-cnt[v1]][cnt[v2]] * c[cnt[u]-1-cnt[v1]-cnt[v2]][cnt[v3]] * dp[v1] * dp[v2] * dp[v3](这个自己推推吧)。化简以后。得到dp[u] = f[cnt[u]-1] / ( f[cnt[v1]] * f[cnt[v2]] * f[cnt[v3]] ) * dp[v1] * dp[v2] * dp[v3] 。我们能够在o(n)的时间复杂度内算出以1节点为根的全部dp值(那么以1为根的答案就算出来了)。以及其它一些辅助信息的值。然后按树的结构往下遍历。分别计算以其它节点为根的答案。以上是网上的思路。我想说的是自己的一点理解。为什么知道每一个子树的拓扑序数目。就能够退出自己的拓扑序数目呢。事实上非常好理解的。当每一个子树的拓扑序定下来之后。确定总顺序的时候。

也就是要得到一个长度为cnt[u]拓扑序列。

对于子树i。

也有一个长度为cnt[i]拓扑序列,所以就要在cnt[u]里找cnt[i]个位置。其它子树再在剩下的子树里找。

还有换根的时候该怎么推导。先写出

dp[u]’=dp[u]*(n-sz[v]-1)!*sz[v]!/((n-1)!*dp[v])
dp[v]’=dp[v]*(n-1)!*dp[u]’/((sz[v]-1)!*(n-sz[v])!)。

带入dp[u]’就能够约掉非常多东西了。所以推公式的时候不要急着得到最后答案。还有就是为什么答案数就是拓扑序数的平方。

由于信息传回去的时候就是你拓扑序嘛。和拓扑序数目一样的。

每个正拓扑序能够和一个逆拓扑序组合。所以就有平方种啦。

具体见代码:

#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000010;
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long ll;
const ll mod=1e9+7;
ll fac[maxn],dp[maxn],ans;
int cnt,sz[maxn],n;
struct node
{
    int v;
    node *next;
} ed[maxn<<1],*head[maxn];
void adde(int u,int v)
{
    ed[cnt].v=v;
    ed[cnt].next=head[u];
    head[u]=&ed[cnt++];
}
ll pow_mod(ll x,int k)
{
    ll base=x,ret=1;
    while(k)
    {
        if(k&1)
            ret=(ret*base)%mod;
        base=(base*base)%mod;
        k>>=1;
    }
    return ret;
}
ll ni(ll x){    return pow_mod(x,mod-2);    }
void dfs(int fa,int u)
{
    ll tp;
    dp[u]=tp=sz[u]=1;
    for(node *p=head[u];p!=NULL;p=p->next)
    {
        int v=p->v;
        if(v==fa)
            continue;
        dfs(u,v);
        tp=(tp*ni(fac[sz[v]]))%mod;
        dp[u]=(dp[u]*dp[v])%mod;
        sz[u]+=sz[v];
    }
    dp[u]=(dp[u]*fac[sz[u]-1]%mod*tp)%mod;
}
void solve(int fa,int u,ll tp)
{
    ll tt;
    ans=(ans+tp*tp%mod)%mod;
    for(node *p=head[u];p!=NULL;p=p->next)
    {
        int v=p->v;
        if(v==fa)
            continue;
        tt=(tp*fac[n-sz[v]-1]%mod*fac[sz[v]])%mod;
        tt=(tt*ni(fac[sz[v]-1])%mod*ni(fac[n-sz[v]]))%mod;
        solve(u,v,tt);
    }
}
int main()
{
    int t,i,u,v,rt;

    fac[0]=fac[1]=1;
    for(i=2;i<maxn;i++)
        fac[i]=(i*fac[i-1])%mod;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        cnt=0,ans=0;
        for(i=1;i<=n;i++)
            head[i]=NULL;
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            adde(u,v);
            adde(v,u);
        }
        rt=(n+1)/2;
        dfs(-1,rt);
        solve(-1,rt,dp[rt]);
        printf("%I64d\n",ans);
    }
    return 0;
}


版权声明:本文博主原创文章,博客,未经同意不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116894.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • idea激活码在哪输入(注册激活)「建议收藏」

    (idea激活码在哪输入)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/ide…

    2022年3月26日
    569
  • Java基础问题整理「建议收藏」

    备注:针对基本问题做一些基本的总结,不是详细解答!1.HashMap和ConcurrentHashMap区别(必考)2.ConcurrentHashMap的数据结构(必考)3.高并发HashMap的环是如何产生的4.HashMap1.7与HashMap1.8的区别,从数据结构上、Hash值的计算上、链表数据的插入方法、内部Entry类的实现上分析?5.Hash1.7是基于数组…

    2022年4月6日
    37
  • noip2014普及组初赛答案_观光3路公交车路线

    noip2014普及组初赛答案_观光3路公交车路线话说,我终于AC了这个题这是一个贪心,说实话开始做的时候……完全没看出来QAQ。。可能有人说这是个dp,但这真不是(dalao请无视)这真的只是个贪心。。。。首先对于每个点当然是能走就走,不能走就等待,这是无法控制的。所以只考虑氮气加速器加在哪里可以使时间总和尽量少。所以如果选择加速,可能会使后面等待的时间更长,或者更短,对后面都会有影响。但是沿着一条边加速会影响后面的所…

    2022年9月24日
    3
  • java编程软件下载_Ee Java(Java编程软件) V1.1.0 官方版

    java编程软件下载_Ee Java(Java编程软件) V1.1.0 官方版EeJava是一款专业实用的Java中文编程软件,基于java技术开发,继承其强大、稳定、安全、高效、跨平台等多方面的优点,目前是内测版本,后期会开源!【使用说明】将下载的jdkJRE替换软件目录中的JDKJRE配置环境变量1.安装完成后,右击我的电脑,点击属性,选择高级系统设置2.选择高级选项卡,点击环境变量在系统变量中设置3项属性,JAVA_HOME、PA…

    2022年7月7日
    21
  • 解决SqlTransaction用尽的问题(SQL处理超时)

    解决SqlTransaction用尽的问题(SQL处理超时)有时候程序处理的数据量比较小时,四平八稳,一切安然无恙,但数据量一大,原先潜伏的问题就暴露无遗了。原访问数据库的代码为: 1SqlConnection conn = new SqlConnection(strConn); 2conn.Open(); 3SqlTransaction trans = conn.BeginTransaction(); 4try 5{ 6    CEngine.Exe…

    2022年5月18日
    38
  • pycharm运行环境配置_pycharm安装django

    pycharm运行环境配置_pycharm安装django1.安装Python前往https://www.python.org/downloads/release/python-383/,根据环境下载对应的python安装包安装。2.安装pycharmPycharm是一个可用作工程开发的工具。前往https://www.jetbrains.com/pycharm/,点击下图中的下载链接:分Professional和Community两个版本,deployment等功能仅前者开放。·Community版本:免费。·Professi

    2022年8月29日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号