树状数组+概率论,ABC380G - Another Shuffle Window

news2024/11/17 12:23:03

目录

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

二、解题报告

1、思路分析

2、复杂度

3、代码详解


一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

G - Another Shuffle Window


二、解题报告

1、思路分析

不难用树状数组计算全局逆序对tot

我们可以在滑窗过程中维护当前 k-子数组的逆序对数目cur(不计入滑窗内的数和滑窗外的数字构成的逆序对)

对于滑窗的每个时刻,滑窗外元素对逆序对的贡献为 tot - cur

也就是说,每个滑窗,不带滑窗内会有tot - cur个逆序对

每个滑窗这一部分的贡献为 (tot - cur) * (n - k + 1),因为 n - k + 1个滑窗等概率,所以贡献比例相同,这一部分的答案我们滑窗过程中直接累加

关键在于如何理解滑窗内元素之间的逆序对数目?

我们发现我们只需计算子数组内产生的逆序对,而对于一个数组而言,数组内任意两个数之间构成逆序对的数目为 1 / 2,而 k-数组 pair 的数目为 k * (k - 1) / 2,每个pair 贡献1个逆序对的概率为1/2,根据二项分布的数学期望计算公式:E = np可得,k-数组的逆序对贡献期望为 k * (k - 1) / 4

那么答案就是把两部分加起来,详细看代码

2、复杂度

时间复杂度: O(NlogN)空间复杂度:O(N)

3、代码详解

 ​
#include <bits/stdc++.h>

// #define DEBUG

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

constexpr int inf32 = 1E9 + 7;
constexpr i64 inf64 = 1E18 + 7;

template<class T>
constexpr T power(T a, i64 b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}

constexpr i64 mul(i64 a, i64 b, i64 p) {
    i64 res = a * b - i64(1.L * a * b / p) * p;
    res %= p;
    if (res < 0) {
        res += p;
    }
    return res;
}
template<i64 P>
struct MLong {
    i64 x;
    constexpr MLong() : x{} {}
    constexpr MLong(i64 x) : x{norm(x % getMod())} {}
    
    static i64 Mod;
    constexpr static i64 getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(i64 Mod_) {
        Mod = Mod_;
    }
    constexpr i64 norm(i64 x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr i64 val() const {
        return x;
    }
    explicit constexpr operator i64() const {
        return x;
    }
    constexpr MLong operator-() const {
        MLong res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MLong inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MLong &operator*=(MLong rhs) & {
        x = mul(x, rhs.x, getMod());
        return *this;
    }
    constexpr MLong &operator+=(MLong rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MLong &operator-=(MLong rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MLong &operator/=(MLong rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MLong operator*(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MLong operator+(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MLong operator-(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MLong operator/(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MLong &a) {
        i64 v;
        is >> v;
        a = MLong(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MLong &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MLong lhs, MLong rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MLong lhs, MLong rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
i64 MLong<0LL>::Mod = i64(1E18) + 9;

template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(i64 x) : x{norm(x % getMod())} {}
    
    static int Mod;
    constexpr static int getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr int norm(int x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MInt &operator*=(MInt rhs) & {
        x = 1LL * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
        i64 v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
int MInt<0>::Mod = 998244353;

template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

constexpr int P = 998244353;
using Z = MInt<P>;

template<typename T>
class FenWick {
private:
    int n;
    std::vector<T> tr;
public:
    FenWick(int _n) : n(_n), tr(_n + 1) 
    {}
    FenWick(const std::vector<T> &_init) : FenWick(_init.size()) {
        init(_init);
    }

    void init(const std::vector<T> &_init) {
        for (int i = 1; i <= n; ++ i) {
            tr[i] += _init[i - 1];
            int j = i + (i & -i);
            if (j <= n)
                tr[j] += tr[i];
        }
    }

    void add(int x, int k) {
        for (; x <= n; x += x & -x) tr[x] += k;
    }

    void add(int l, int r, T k) {
        add(l, k);
        if (r + 1 <= n)
            add(r + 1, -k);
    }

    T query(int x) const {
        T res = T{};
        for (; x; x &= x - 1) { 
            res += tr[x];
        }
        return res;
    }

    T query(int l, int r) const {
        if (l > r) return T{};
        return query(r) - query(l - 1);
    }

    int select(int k) {
        int x = 0;
        T cur{};
        for (int i = 1 << std::__lg(n); i; i /= 2) {
            if (x + i <= n && cur + tr[x + i] < k) {
                x += i;
                cur = cur + tr[x];
            }
        }
        return x + 1;
    }

    void clear() {
        tr.assign(n + 1, T{});
    }
};

void solve() {
    int n, k;
    std::cin >> n >> k;

    std::vector<int> p(n);
    for (int i = 0; i < n; ++ i) {
        std::cin >> p[i];
    }

    FenWick<Z> fen(n);

    Z tot = 0;
    for (int i = n - 1; ~i; -- i) {
        tot += fen.query(p[i]);
        fen.add(p[i], 1);
    }

    fen.clear();
    Z cur = 0;

    for (int i = k - 1; ~i; -- i) {
        cur += fen.query(p[i]);
        fen.add(p[i], 1);
    }

    Z ans = tot - cur;

    for (int i = 0; i + k < n; ++ i) {
        fen.add(p[i], -1);
        cur -= fen.query(p[i]);
        cur += fen.query(p[i + k], n);
        fen.add(p[i + k], 1);
        ans += tot - cur;
    }

    std::cout << (ans * Z(n - k + 1).inv() + Z(4).inv() * Z(k) * Z(k - 1)) << '\n';
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

#ifdef DEBUG
    int START = clock();
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int t = 1;
    // std::cin >> t;

    while (t --) {
        solve();
    }
#ifdef DEBUG
    std::cerr << "run-time: " << clock() - START << '\n';
#endif
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LSTM(长短期记忆网络)详解

1️⃣ LSTM介绍 标准的RNN存在梯度消失和梯度爆炸问题&#xff0c;无法捕捉长期依赖关系。那么如何理解这个长期依赖关系呢&#xff1f; 例如&#xff0c;有一个语言模型基于先前的词来预测下一个词&#xff0c;我们有一句话 “the clouds are in the sky”&#xff0c;基于&…

麒麟nginx配置

一、配置负载均衡 配置麒麟的yum源 vim /etc/yum.repos.d/kylin_aarch64.repo Copy 删除原来内容&#xff0c;写入如下yum源 [ks10-adv-os] name Kylin Linux Advanced Server 10 - Os baseurl http://update.cs2c.com.cn:8080/NS/V10/V10SP2/os/adv/lic/base/aarch64/ …

AI工业大模型报告:体系架构、关键技术与典型应用

研究意义 随着新一代人工智能的发展, 大模型&#xff08;如 GPT-4o 等&#xff09;凭借大规模训练数据、网络参数和算 力涌现出强大的生成能力、泛化能力和自然交互能力, 展现出改变工业世界的巨大潜力. 尽管大模型 已在自然语言等多个领域取得突破性进展, 但其在工业应用中的…

华为ensp实验二--mux vlan的应用

一、实验内容 1.实验要求&#xff1a; 在交换机上创建三个vlan&#xff0c;vlan10、vlan20、vlan100&#xff0c;将vlan100设置为mux-vlan&#xff0c;将vlan10设置为group vlan&#xff0c;将vlan20设置为separate vlan&#xff1b;实现vlan10的设备在局域网内可以进行互通&…

【微软:多模态基础模型】(1)从专家到通用助手

欢迎关注【youcans的AGI学习笔记】原创作品 【微软&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微软&#xff1a;多模态基础模型】&#xff08;3&#xff09;视觉生成 【微…

学习threejs,使用第一视角控制器FirstPersonControls控制相机

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️第一视角控制器FirstPerson…

GitLab 降级安装出现 500 错误,如何解决?

本文分享 GitLab 中文版在降级的过程中出现 500 错误的修复方法。 写在前面 强烈不建议大家自行降级&#xff0c;如果真有降级需求&#xff0c;要么自己能力过硬&#xff0c;要么寻求专业服务【https://dl.gitlab.cn/cm33bsfv】&#xff0c;要不出问题很麻烦&#xff01; 问…

《Representing Scenes asNeural Radiance Fields for View Synthesis》论文解析——NeRF

一、论文简介 NeRF这篇论文提出了一种通过优化一个连续的5D体积场景函数来合成复杂场景新视图的方法。该算法使用一个全连接的深度网络来表示场景&#xff0c;输入是单一连续的5D坐标&#xff08;空间位置和观察方向&#xff09;&#xff0c;输出是该位置的体积密度和依赖于观察…

精通rust宏系列教程-调试过程宏

Rust过程性宏是该语言最令人兴奋的特性之一。它们让你能够在编译时注入代码&#xff0c;但与单态泛型所使用的方法不同。使用非常特殊的包&#xff08;crate&#xff09;&#xff0c;让你可以完全从头开始构建新代码。本文从简单示例开始&#xff0c;逐步分解&#xff0c;也会详…

035_Progress_Dialog_in_Matlab中的进度条对话框

进度条 概念 在使用Matlab开发界面时&#xff0c;有一个很好用的工具就是进度条。在计算过程中&#xff0c;为用户提供计算进度的反馈是改善用户体验的重要手段。 一项进行的计算任务&#xff0c;如果其总体进度是比较容易量化&#xff0c;则可以按照0%~100%的方式&#xff0…

动态规划:计算技术中的核心【精确与效率并存】

写在前面 博客来源&#xff1a;翻译自youtube高赞技术视频&#xff0c;并精加工和细化。 适合阅读&#xff1a;想要搞懂动态规划的小伙伴~ 动态规划是一项杰出的计算技术&#xff0c;它既保留了穷举法的精确性&#xff0c;又吸收了贪心算法的高效率。 它主要应用于两个领域…

【JavaSE线程知识总结】

多线程 一.创建线程1.多线程创建方式一(Thread)2.多线程创键方式二(Runnable)3.线程创建方式三 二.线程安全问题解决办法1.使用同步代码块synchornized 2 .使用Lock解决线程安全问题 三.总结 线程就是程序内部的一条执行流程 一.创建线程 常用的方法 Thread.currentThread()…

Leetcode - 周赛423

目录 一&#xff0c;3349. 检测相邻递增子数组 I 二&#xff0c;3350. 检测相邻递增子数组 II 三&#xff0c;3351. 好子序列的元素之和 四&#xff0c;3352. 统计小于 N 的 K 可约简整数 一&#xff0c;3349. 检测相邻递增子数组 I 本题有两种做法&#xff1a; 先求出递增…

boost之property

简介 property在boost.graph中有使用&#xff0c;用于表示点属性或者边属性 结构 #mermaid-svg-56YI0wFLPH0wixrJ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-56YI0wFLPH0wixrJ .error-icon{fill:#552222;}#me…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-25

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

paddle表格识别数据制作

数据格式 其中主要数据有两个一个表格结构的检测框&#xff0c;一个是tokens&#xff0c;注意的地方是 1、只能使用双引号&#xff0c;单引号不行 2、使用带引号的地方是tokens里面 "<tr>", "<td", " colspan2", ">",&quo…

Java 全栈知识体系

包含: Java 基础, Java 部分源码, JVM, Spring, Spring Boot, Spring Cloud, 数据库原理, MySQL, ElasticSearch, MongoDB, Docker, k8s, CI&CD, Linux, DevOps, 分布式, 中间件, 开发工具, Git, IDE, 源码阅读&#xff0c;读书笔记, 开源项目...

WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇

WebRTC视频 01 - 视频采集整体架构 WebRTC视频 02 - 视频采集类 VideoCaptureModule WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇 WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇&#xff08;本文&#xff09; WebRTC视频 05 - 视频采集类 VideoCaptureDS 下篇 一、前言…

任务调度中心-XXL-JOB使用详解

目录 详解 调度中心 执行器 原理 快速入门 源码仓库地址 1.初始化数据库 2.配置调度中心 1.解压源码 2.需改配置文件 3.启动调度中心 3.配置执行器 1.引入pom依赖 2.修改配置文件 3.执行器组件配置 4.部署执行器项目 4.开发第一个任务 BEAN模式&#xff08;类…

如何搭建一台邮箱服务器,配置满分邮箱

如何搭建一台邮箱服务器,配置满分邮箱 搭建一台个人邮箱服务器听上去非常有技术含量&#xff0c;但只要准备工作充分&#xff0c;并且选择合适的软件&#xff0c;配置满分的邮箱&#xff0c;其实并没有想象中那么困难。在这篇文章中&#xff0c;我们将介绍搭建邮箱服务器的 必备…