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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 五万字总结,深度学习基础。「建议收藏」

    五万字总结,深度学习基础。「建议收藏」文章目录1基本概念1.1神经网络组成?1.2神经网络有哪些常用模型结构?1.3如何选择深度学习开发平台?1.4为什么深层神经网络难以训练?1.5深度学习和机器学习的异同?2网络操作与计算2.1前向传播与反向传播?2.2如何计算神经网络的输出?2.3如何计算卷积神经网络输出值?2.4如何计算Pooling层输出值输出值?2.5实例理解反向传播2.6神经网络更“深”有什么意义?3超参数3.1什么是超参数?3.2如何寻找超参数的最优值?3.3超参数搜索一般过程?4激活函数4

    2022年5月21日
    39
  • 深度学习PyTorch,TensorFlow中GPU利用率较低,CPU利用率很低,且模型训练速度很慢的问题总结与分析

    深度学习PyTorch,TensorFlow中GPU利用率较低,CPU利用率很低,且模型训练速度很慢的问题总结与分析在深度学习模型训练过程中,在服务器端或者本地pc端,输入nvidia-smi来观察显卡的GPU内存占用率(Memory-Usage),显卡的GPU利用率(GPU-util),然后采用top来查看CPU的线程数(PID数)和利用率(%CPU)。往往会发现很多问题,比如,GPU内存占用率低,显卡利用率低,CPU百分比低等等。接下来仔细分析这些问题和处理办法。1.GPU内存占用率问…

    2022年6月12日
    216
  • 高分1(GF1)、高分2(GF2)卫星数据大气校正[通俗易懂]

    高分1(GF1)、高分2(GF2)卫星数据大气校正[通俗易懂]KEYWORDS:GF1,GF2,RSD,大气校正,遥感软件0.RSD大气校正RSD是李国春教授团队开发的一款遥感数处理软件。其大气校正模块是参照USGSLaSRC大气校正流程,使用VC++重新改写并在Windows平台实现的内置大气校正功能。1.原理与方法RSD大气校正是应用6SV大气辐射模型原理实现的RSD遥感平台内置软件功能。其对Landsat8OLI大气校正部分延续了LaSRC的校…

    2022年10月9日
    1
  • 小白能读懂的 《手把手教你学DSP(TMS320X281X)》第七章 CPU定时器

    小白能读懂的 《手把手教你学DSP(TMS320X281X)》第七章 CPU定时器1定时器概念计时工具,用来准确控制时间。

    2022年6月7日
    32
  • Git规范:Git提交规范

    Git规范:Git提交规范1 Commitmessag 格式 type scope subject 1 type 必须 作用 用于说明 Gitcommit 的类别 只允许使用下面的标识 feat 新功能 feature fix to 修复 bug 可以是 QA QualityAssur 发现的 BUG 也可以是研发自己发现的 BUG 备注 fix 产生 diff 并自动修复此问题 适合于一次提交直接修复问题 to 只产生 diff 不自动修复此问题 subject scope type

    2025年11月5日
    3
  • 弗洛伊德算法—–最短路径算法(一)

    弗洛伊德算法—–最短路径算法(一)学习此算法的原因:昨天下午遛弯的时候,碰到闺蜜正在看算法,突然问我会不会弗洛伊德算法?我就顺道答应,然后用了半个小时的时间,学习了此算法,并用5分钟讲解给她听,在此也分享给各位需要的朋友,让你们在最短的时间内,透彻的掌握该算法。RobertW.Floyd(罗伯特弗洛伊德)1962年在“CommunicationoftheACM”上发表了该算法,同年StephenWarsha…

    2022年6月4日
    385

发表回复

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

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