当前位置: 首页 > news >正文

【算法题解】拓扑序计数+树形DP

拓扑序计数+树形DP

题目

链接:https://ac.nowcoder.com/acm/contest/38630/F

image-20220904192158381

思路

每个公司是一棵树,有n家公司,可以将这n家公司连到一个虚拟的根上。总共的排队方案就等于这个棵的排队方案树。为了满足排队是顺序的,所以我们要求的就是这棵树的拓扑序个数。用树形DP来求解。

f[u]: 以u为根的子树的拓扑序数

sz[u]: 以u为根的子树的大小(节点的数量)

如何计算一个棵的拓扑序数?

我们先来看只有两个子树的情况:

image-20220904195600066

如上图所示,1号节点一定是第1为,那么剩下还有3位置,有三种可能:

  • 1 2 3 4
  • 1 3 2 4
  • 1 2 4 3

这就用到了概率论的知识,有三个盒子,从中要选2个盒子给2、4放置,并且是按照顺序的2 4放置,因为是拓扑序,所以每个子树的相对顺序是一定的,所以最后计算的结果就是:
f [ u ] = f [ v 1 ] ⋅ f [ v 2 ] ⋅ C ( s z [ v 1 ] + s z [ v 2 ] , s z [ v 1 ] ) f[u]=f[v1]⋅f[v2]⋅C(sz[v1]+sz[v2],sz[v1]) f[u]=f[v1]f[v2]C(sz[v1]+sz[v2],sz[v1])
当树为二叉树时,将两个子树v1,v2进行合并:即先把各子树的方案数乘起来算出总方案,然后考虑各子树元素的相对排列顺序,即在总的节点个数中选sz[v1]sz[v1]个位置,剩下的顺序就固定了,保证每颗子树的相对拓扑序不变。

image-20220904200620793

如何计算组合数

在这里插入图片描述

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef priority_queue<int, vector<int>, less<int>> Q;
#define x first
#define y second
#define endl '\n'
#define ppb pop_back
#define pb push_back
#define pf push_front
#define YES cout << "YES" << endl
#define Yes cout << "Yes" << endl
#define yes cout << "yes" << endl
#define NO cout << "NO" << endl
#define No cout << "No" << endl
#define no cout << "no" << endl
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define mset(x, a) memset(x, a, sizeof(x))
#define rep(i, l, r) for (LL i = l; i <= (r); ++i)
#define per(i, r, l) for (LL i = r; i >= (l); --i)
const int N = 1e5 + 10, inf = 0x3f3f3f3f, mod = 1e9 + 7;
vector<int> v[N];
int n;
int sz[N];
ll fac[N];
ll inv[N];
ll f[N];
ll qsm(ll a, ll b)
{
    ll ans = 1;
    while (b)
    {
        if (b & 1)
            ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
void dfs(int u)
{
    f[u] = 1;
    sz[u] = 1;
    for (int i = 0; i < v[u].size(); i++)
    {
        int j = v[u][i];
        dfs(j);
        sz[u] += sz[j];
        f[u] = (f[u] * f[j]) % mod * inv[sz[j]] % mod;
    }
    f[u] = f[u] * fac[sz[u] - 1] % mod;
}
void solve()
{
    fac[0] = 1;
    inv[0] = 1;
    for (int i = 1; i < N; i++)
    {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = inv[i - 1] * qsm(i, mod - 2) % mod;
    }
    cin >> n;
    ll ans = 1;
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        int c;
        cin >> c;
        v[0].pb(cnt + 1);
        for (int j = 2; j <= c; j++)
        {
            int u;
            cin >> u;
            v[cnt + u].pb(cnt + j);
        }
        cnt += c;
    }
    dfs(0);
    cout << f[0];
}
signed main()
{
#ifdef Xin
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    int T = 1;
    while (T--)
        solve();
    return 0;
}

感谢大佬的文章:

  • http://wyqz.top/p/2852940489.html
  • https://www.acwing.com/solution/content/16482/

相关文章:

  • 优雅编码之——传统项目中,使用openfeign替换掉项目中的httpclient
  • 【ENVI精讲】处理专题五:基于像元二分模型的植被覆盖度反演
  • Docker 官方镜像Tomcat 无法访问 解决方案
  • Qt使用OpenCv
  • 【JavaEE进阶系列 | 从小白到工程师】泛型的详细介绍使用与类型通配符,直接上手
  • java毕业设计论坛管理系统mybatis+源码+调试部署+系统+数据库+lw
  • k8s对接ceph,ceph-csi方式
  • Kubernetes控制平面组件:Kubelet
  • 忘记背后,努力面前【开学季flag】
  • 2022-09-04 瞒春 学习笔记
  • 谷歌?亲斤手不推荐 选它就对了
  • Ubuntu20.04下载opencv3.4--未完善
  • (待修改)PyG安装步骤
  • vue2中vant适配-把px都换算成rem
  • 猿创征文|Spring5梦开始的地方:入门必看
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【React系列】如何构建React应用程序
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • js面向对象
  • js写一个简单的选项卡
  • Netty 4.1 源代码学习:线程模型
  • Rancher-k8s加速安装文档
  • vue的全局变量和全局拦截请求器
  • 初识 webpack
  • 免费小说阅读小程序
  • 排序算法学习笔记
  • 深度解析利用ES6进行Promise封装总结
  • 使用 QuickBI 搭建酷炫可视化分析
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 我的业余项目总结
  • 我有几个粽子,和一个故事
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 原生JS动态加载JS、CSS文件及代码脚本
  • ​一些不规范的GTID使用场景
  • # 安徽锐锋科技IDMS系统简介
  • #Linux(Source Insight安装及工程建立)
  • (6)STL算法之转换
  • (pytorch进阶之路)扩散概率模型
  • (windows2012共享文件夹和防火墙设置
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • (转载)Linux网络编程入门
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • **PHP二维数组遍历时同时赋值
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET Framework与.NET Framework SDK有什么不同?
  • .net MVC中使用angularJs刷新页面数据列表
  • .Net Web窗口页属性
  • .net2005怎么读string形的xml,不是xml文件。
  • .Net6 Api Swagger配置
  • .Net程序帮助文档制作