Codeforces Round 926 F. Sasha and the Wedding Binary Search Tree

F. Sasha and the Wedding Binary Search Tree

1
2

题意

给定一颗二叉搜索树,规定树上的所有点的点权都在范围 [ 1 , C ] [1, C] [1,C] 内,树上的某些节点点权已知,某些节点点权未知,求出合法的二叉搜索树的数量

思路

由于是二叉搜索树,所以左子树的点权小于等于右子树的点权,我们先进行一次先序遍历,得到一个 o r d e r order order 遍历顺序的数组,其中某些段是未知的点权,我们可以通过其左端点和右端点的点权来约束这些未知点的点权

假如这个未知段左边紧邻的第一个已知点权为 L L L,右边紧邻的第一个已知点权为 R R R,那么显然我们这个未知段的点权是 [ L , R ] [L,R] [L,R] 的,假设未知段长度为 l e n len len,问题等价于选出 l e n len len 个数,按照非递减的顺序摆放的方案数,允许重复数字出现。

我们将问题再转化一下,由于是非递减,所以一定有: v a l i ≤ v a l i + 1 val_i \leq val_{i + 1} valivali+1,那么这一段的差分数组一定是大于等于 0 0 0 的一段,并且总和为 R − L R - L RL,要加上最后一个 R R R 的位置,长度变为 l e n + 1 len + 1 len+1,例如: L = 2 , R = 5 , l e n = 3 L = 2, R= 5, len = 3 L=2,R=5,len=3,我们构造这样一个方案: 2 , 3 , 3 , 4 , 5 2, 3 , 3, 4, 5 2,3,3,4,5,差分数组为: 2 , 1 , 0 , 1 , 1 2, 1, 0, 1, 1 2,1,0,1,1,忽略第一个位置的话,后面所有元素的和就是 R − L = 3 R - L = 3 RL=3,那么问题成功转化为了:将 R − L R - L RL 个相同小球放入 l e n + 1 len + 1 len+1 个不同盒子中(允许空盒子)的方案数,即为: C R − L + l e n l e n C_{R - L + len}^{len} CRL+lenlen

由于这里 R − L R - L RL 很大,所以不能直接预处理阶乘,注意到 ∑ l e n ≤ n \sum len \leq n lenn,我们只需要利用公式: C R − L + l e n l e n = ( R − L + l e n ) ⋅ ( R − L + l e n − 1 ) ⋅ . . . ⋅ ( R − L + 1 ) l e n ! C_{R - L + len}^{len} = \dfrac{(R - L + len) \cdot (R - L + len - 1) \cdot ... \cdot (R - L + 1)}{len!} CRL+lenlen=len!(RL+len)(RL+len1)...(RL+1) 来计算即可

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;

const int INF=0x3f3f3f3f;
const long long INFLL=1e18;

typedef long long ll;

template<class T>
constexpr T power(T a, ll b){
    T res = 1;
    while(b){
        if(b&1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

constexpr ll mul(ll a,ll b,ll mod){ //快速乘,避免两个long long相乘取模溢出
    ll res = a * b - ll(1.L * a * b / mod) * mod;
    res %= mod;
    if(res < 0) res += mod; //误差
    return res;
}

template<ll P>
struct MLL{
    ll x;
    constexpr MLL() = default;
    constexpr MLL(ll x) : x(norm(x % getMod())) {}

    static ll Mod;
    constexpr static ll getMod(){
       if(P > 0) return P;
       return Mod;
    }

    constexpr static void setMod(int _Mod){
       Mod = _Mod;
    }
    constexpr ll norm(ll x) const{
       if(x < 0){
           x += getMod();
       }
       if(x >= getMod()){
           x -= getMod();
       }
       return x;
    }
    constexpr ll val() const{
       return x;
    }
    explicit constexpr operator ll() const{ 
       return x; //将结构体显示转换为ll类型: ll res = static_cast<ll>(OBJ)
    }
    constexpr MLL operator -() const{ //负号,等价于加上Mod
       MLL res;
       res.x = norm(getMod() - x);
       return res;
    }
    constexpr MLL inv() const{
       assert(x != 0);
       return power(*this, getMod() - 2); //用费马小定理求逆
    }
    constexpr MLL& operator *= (MLL rhs) & { //& 表示“this”指针不能指向一个临时对象或const对象
       x = mul(x, rhs.x, getMod()); //该函数只能被一个左值调用
       return *this;
    }
    constexpr MLL& operator += (MLL rhs) & {
       x = norm(x + rhs.x);
       return *this;
    }
    constexpr MLL& operator -= (MLL rhs) & {
       x = norm(x - rhs.x);
       return *this;
    }
    constexpr MLL& operator /= (MLL rhs) & {
       return *this *= rhs.inv();
    }
    friend constexpr MLL operator * (MLL lhs, MLL rhs){
       MLL res = lhs;
       res *= rhs;
       return res;
    }
    friend constexpr MLL operator + (MLL lhs, MLL rhs){
       MLL res = lhs;
       res += rhs;
       return res;
    }
    friend constexpr MLL operator - (MLL lhs, MLL rhs){
       MLL res = lhs;
       res -= rhs;
       return res;
    }
    friend constexpr MLL operator / (MLL lhs, MLL rhs){
       MLL res = lhs;
       res /= rhs;
       return res;
    }
    friend constexpr std::istream& operator >> (std::istream& is, MLL& a){
       ll v;
       is >> v;
       a = MLL(v);
       return is;
    }
    friend constexpr std::ostream& operator << (std::ostream& os, MLL& a){
       return os << a.val();
    }
    friend constexpr bool operator == (MLL lhs, MLL rhs){
       return lhs.val() == rhs.val();
    }
    friend constexpr bool operator != (MLL lhs, MLL rhs){
       return lhs.val() != rhs.val();
    }
};

const ll mod = 998244353;
using Z = MLL<mod>;

struct Comb {
    int n;
    std::vector<Z> _fac;
    std::vector<Z> _invfac;
    std::vector<Z> _inv;

    Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }

    void init(int m) {
        m = std::min(1ll * m, Z::getMod() - 1);
        if (m <= n) return; //已经处理完了需要的长度
        _fac.resize(m + 1);
        _invfac.resize(m + 1);
        _inv.resize(m + 1);

        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _invfac[m] = _fac[m].inv();
        for (int i = m; i > n; i--) { //线性递推逆元和阶乘逆元
            _invfac[i - 1] = _invfac[i] * i;
            _inv[i] = _invfac[i] * _fac[i - 1];
        }
        n = m; //新的长度
    }

    Z fac(int m) {
        if (m > n) init(2 * m);
        return _fac[m];
    }
    Z invfac(int m) {
        if (m > n) init(2 * m);
        return _invfac[m];
    }
    Z inv(int m) {
        if (m > n) init(2 * m);
        return _inv[m];
    }
    Z binom(int n, int m) { //二项式系数
        if (n < m || m < 0) return 0;
        return fac(n) * invfac(m) * invfac(n - m);
    }
} comb;


const int N = 500050;

int L[N], R[N];
ll val[N];
std::vector<ll> order;

void dfs(int u){
    if(~L[u]) dfs(L[u]);
    order.push_back(val[u]);
    if(~R[u]) dfs(R[u]);
}

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin >> t;
    while(t--){
        int n;
        ll C;
        std::cin >> n >> C;
        fore(i, 1, n + 1) std::cin >> L[i] >> R[i] >> val[i];
        order.clear();

        order.push_back(1);
        dfs(1);
        order.push_back(C);

        Z ans = 1;

        int idx = 1;
        while(idx <= n){
            while(idx <= n && ~order[idx]) ++idx;
            int l = order[idx - 1];
            int len = 0;
            while(idx <= n && order[idx] == -1){
                ++idx;
                len += 1;
            }
            int r = order[idx];

            Z res = 1;
            for(int i = r - l + len; i >= r - l + 1; --i) res *= i;

            res *= comb.invfac(len);
            
            ans *= res;
        }

        std::cout << ans << endl;
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/389570.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Web项目利用MybatisPlus进行分页查询

之前在写博客系统前台页面的时候&#xff0c;遇到了利用mp进行分页查询的情况&#xff0c;由于涉及到的知识点相对较为重要&#xff0c;固写一篇博客以此巩固。 一、功能需求 在首页和分类页面都需要查询文章列表。 首页&#xff1a;查询所有的文章分类页面&#xff1a;查询…

隐函数的求导【高数笔记】

1. 什么是隐函数&#xff1f; 2. 隐函数的做题步骤&#xff1f; 3. 隐函数中的复合函数求解法&#xff0c;与求导中复合函数求解法有什么不同&#xff1f; 4. 隐函数求导的过程中需要注意什么&#xff1f;

透光力之珠——光耦固态继电器的独特特点解析

光耦固态继电器作为现代电子控制领域中的重要组件&#xff0c;以其独特的特点在工业、通信、医疗等多个领域得到广泛应用。本文将深入剖析光耦固态继电器的特点&#xff0c;揭示其在电子控制中的卓越性能。 光耦固态继电器的光电隔离技术 光耦固态继电器以其光电隔离技术而脱颖…

深入了解社区店:定义、模式与优势

在当今的商业环境中&#xff0c;社区店正逐渐成为创业者们关注的热点。本文将以我的鲜奶吧店铺为例&#xff0c;深入探讨社区店的定义、模式和优势&#xff0c;为您提供最有价值的干货信息。 1、社区店的定义 社区店是指位于社区内或周边&#xff0c;以服务社区居民为主要目标…

Diffusion Transformer U-Net for MedicalImage Segmentation

用于医学图像分割的扩散变压器U-Net 摘要&#xff1a; 扩散模型在各种发电任务中显示出其强大的功能。在将扩散模型应用于医学图像分割时&#xff0c;存在一些需要克服的障碍:扩散过程调节所需的语义特征与噪声嵌入没有很好地对齐;这些扩散模型中使用的U-Net骨干网对上下文信…

2.15学习总结

2.15 1.聪明的质监员&#xff08;二分前缀和&#xff09; 2.村村通&#xff08;并查集&#xff09; 3.玉蟾宫(悬线法DP) 4.随机排列&#xff08;树状数组逆序对问题&#xff09; 5.增进感情&#xff08;DFS&#xff09; 6.医院设置&#xff08;floyd&#xff09; 聪明的质监员…

P1010 [NOIP1998 普及组] 幂次方题解

题目 任何一个正整数都可以用2的幂次方表示。例如137。 同时约定次方用括号来表示&#xff0c;即ab可表示为a(b)。 由此可知&#xff0c;137可表示为2(7)2(3)2(0)&#xff0c;进一步&#xff1a;72 ( 用2表示)&#xff0c;并且32。 所以137可表示为2(2(2)22(0))2(22(0))2(0…

ESP32学习(4)——电脑远程控制LED灯

1.思路梳理 首先需要让ESP32连接上WIFI 然后创建udp socket 接着接收udp数据 最后解析数据&#xff0c;控制LED 2.代码实现 import network from socket import * from machine import Pin p2Pin(2,Pin.OUT)def do_connect(): #连接wifi wlan network.WLAN(network.STA_IF)…

optee imx8mm

总仓库 git clone https://github.com/Xsyin/imx8mqevk.git -b container_region 替换imx8mqevk中的optee-client git clone https://github.com/nxp-imx/imx-optee-client.git -b lf-5.15.32_2.0.0 用 5.15.32 kernel 会有如下报错&#xff0c;需要将optee os升级到分支 lf-…

MySQL容器的数据挂载

挂载本地目录或文件 可以发现&#xff0c;数据卷的目录结构较深&#xff0c;如果我们去操作数据卷目录会不太方便。在很多情况下&#xff0c;我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似&#xff1a; # 挂载本地目录 -v 本地目录:容器内目录 # 挂载本地…

第9讲重写登录成功和登录失败处理器

重写登录成功和登录失败处理器 common下新建security包&#xff0c;再新建两个类&#xff0c;LoginSuccessHandler和LoginFailureHandler Component public class LoginSuccessHandler implements AuthenticationSuccessHandler {Overridepublic void onAuthenticationSuccess…

请标记你的龙年心愿关键词

昨天外孙陪我游了崇州市白头镇、道民镇&#xff08;竹艺村&#xff09;&#xff0c;见我心情愉悦&#xff0c;今天再陪我去饱览其他风景名胜&#xff0c;所以笔者——本“人民体验官”特别推广人民日报官方微博文化产品《2024年第一批春花开了》《#大年初七#&#xff0c;标记你…

三种输入输出函数

目录 printf函数 scanf函数 getchar函数 putchar函数 gets函数 puts函数 printf函数 当你需要将数据或文本输出到屏幕或其他输出设备时&#xff0c;C语言提供了一个非常有用的函数&#xff0c;即 printf() 函数。它是标准库中定义的函数&#xff0c;用于格式化输出。 pr…

如何监控另一台电脑屏幕画面?如何远程监控电脑屏幕?

在数字化时代&#xff0c;随着远程工作和协作的普及&#xff0c;电脑屏幕监控的需求也日益增长。无论是出于安全考虑、提高员工工作效率&#xff0c;还是确保企业机密的保密性&#xff0c;电脑屏幕监控都成为了企业不可或缺的管理工具。那么&#xff0c;如何监控另一台电脑屏幕…

怎么恢复电脑重装前的数据?介绍几种有效的方法

在日常生活和工作中&#xff0c;电脑已成为我们不可或缺的工具。然而&#xff0c;有时候我们会遇到一些突发情况&#xff0c;比如电脑系统崩溃需要重新安装系统。在这个过程中&#xff0c;我们可能会失去一些重要的数据&#xff0c;比如照片、文档、视频等。这些数据可能包含着…

第三十一回 武行者醉打孔亮 锦毛虎义释宋江-解压文件但不重复解压

武松发现蜈蚣岭寺庙里一个人搂着女的看月亮&#xff0c;就把那个人和他的道童都杀了。原来那个人叫飞天蜈蚣王道人&#xff0c;那女的是被掳来的&#xff0c;她将一包金银给武松&#xff0c;武松没有要。 就像武松在处理问题时展现出的智慧和决断力&#xff0c;现代IT技术同样…

使用骨传导耳机真的不损伤听力吗?哪些人群适合购买骨传导耳机?

如果是正确的使用骨传导耳机&#xff0c;是不会损伤听力的&#xff0c;因为骨传导耳机采用开放式佩戴&#xff0c;而且传声方式不经过耳道和耳膜&#xff0c;是通过人体骨骼来传递声音&#xff0c;不会损伤耳膜&#xff0c;所以不会损伤听力。 由于骨传导耳机的特殊性&#xff…

SG3225VEN晶体振荡器SPXO

SG3225VEN是爱普生的一款LVDS输出差分晶振&#xff0c;小体积晶振尺寸3.2*2.5mm的石英晶体振荡器&#xff0c;六脚贴片晶振&#xff0c;电源电压2.5V、3.3V&#xff0c;频率范围25mhz ~ 500mhz&#xff0c;工作温度可达到- 40℃~ 105℃&#xff0c;该产品具有超小型&#xff0…

【深入理解BEVFormer】BEVFormer

任务场景 多模态融合和多传感器融合 BEV&#xff1a;鸟瞰图 这个特征空间与每个视角都相关 早期是用后融合&#xff0c;目前比较流行的是特征级融合 自身运动补偿&#xff1a;如果按照像素点进行特征对齐&#xff0c;需要指定偏移量 x y两个方向 特征空间是自己定义的&#xf…

使用REQUESTDISPATCHER对象调用错误页面

使用REQUESTDISPATCHER对象调用错误页面 问题陈述 InfoSuper公司已经创建了一个动态网站。发生错误时,浏览器中显示的堆栈跟踪很难理解。公司的系统分析师David Wong让公司的软件程序员Don Allen创建自定义错误页面。servlet引发异常时,应使用RequestDisapatcher对象向自定义…