竞技编程中的快速输入/输出

2023-11-27

我在竞争性编程竞赛的解决方案中多次遇到过这个特定的代码片段。我了解此代码的基本用途来克服时间限制,但我想更深入地了解它。我知道 unistd.h 可以访问系统调用包装函数,例如 fork、pipe 和 I/O 原语(读、写等)。

如果有人可以解释或指导我找到可以帮助我进一步理解它的资源,那就太好了。

#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
class FastInput {
public:
    FastInput() {
        m_dataOffset = 0;
        m_dataSize = 0;
        m_v = 0x80000000;
    }
    uint32_t ReadNext() {
        if (m_dataOffset == m_dataSize) {
            int r = read(0, m_buffer, sizeof(m_buffer));
            if (r <= 0) return m_v;
            m_dataOffset = 0;
            m_dataSize = 0;
            int i = 0;
            if (m_buffer[0] < '0') {
                if (m_v != 0x80000000) {
                    m_data[m_dataSize++] = m_v;
                    m_v = 0x80000000;
                }
                for (; (i < r) && (m_buffer[i] < '0'); ++i);
            }
            for (; i < r;) {
                if (m_buffer[i] >= '0') {
                    m_v = m_v * 10 + m_buffer[i] - 48;
                    ++i;
                } else {
                    m_data[m_dataSize++] = m_v;
                    m_v = 0x80000000;
                    for (i = i + 1; (i < r) && (m_buffer[i] < '0'); ++i);
                }
            }
        }
        return m_data[m_dataOffset++];
    }
public:
    uint8_t m_buffer[32768];
    uint32_t m_data[16384];
    size_t m_dataOffset, m_dataSize;
    uint32_t m_v;
};
class FastOutput {
public:
    FastOutput() {
        m_dataOffset = 0;
    }
    ~FastOutput() {
    }
    void Flush() {
        if (m_dataOffset) {
            if (write(1, m_data, m_dataOffset));
            m_dataOffset = 0;
        }
    }
    void PrintUint(uint32_t v, char d) {
        if (m_dataOffset + 11 > sizeof(m_data)) Flush();
        if (v < 100000) {
            if (v < 1000) {
                if (v < 10) {
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 1;
                } else if (v < 100) {
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 2;
                } else {
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 3;
                }
            } else {
                if (v < 10000) {
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 4;
                } else {
                    m_data[m_dataOffset + 4] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 5;
                }
            }
        } else {
            if (v < 100000000) {
                if (v < 1000000) {
                    m_data[m_dataOffset + 5] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 4] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 6;
                } else if (v < 10000000) {
                    m_data[m_dataOffset + 6] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 5] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 4] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 7;
                } else {
                    m_data[m_dataOffset + 7] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 6] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 5] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 4] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 8;
                }
            } else {
                if (v < 1000000000) {
                    m_data[m_dataOffset + 8] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 7] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 6] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 5] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 4] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 9;
                } else {
                    m_data[m_dataOffset + 9] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 8] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 7] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 6] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 5] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 4] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 3] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 2] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 1] = v - v / 10 * 10 + 48;
                    v /= 10;
                    m_data[m_dataOffset + 0] = v + 48;
                    m_dataOffset += 10;
                }
            }
        }
        m_data[m_dataOffset++] = d;
    }
    void PrintChar(char d) {
        if (m_dataOffset + 1 > sizeof(m_data)) Flush();
        m_data[m_dataOffset++] = d;
    }
    void ReplaceChar(int offset, char d) {
        m_data[m_dataOffset + offset] = d;
    }
public:
    uint8_t m_data[32768];
    size_t m_dataOffset;
};

还有一件事:在生产级代码中采用类似的技术是一种好的做法吗?


在生产级代码中采用类似的技术是一种好的做法吗?

不会。重新实现轮子会导致错误。错误需要额外的开发时间并且需要花费金钱。

可以帮助我进一步理解它。

如果你看不懂代码,那么代码就写得不好。代码是由人类编写的,也是为人类编写的。如果另一个程序员不能很快理解代码,可能会出现大问题。这种想法(“为人类编写”)背后的基本原理很简单:开发时间成本很高,不可读的代码会增加开发时间。

有问题的代码片段利用了几种不良的编码实践:

  1. 匈牙利表示法(在区分大小写的表示法中不需要这样做,尤其是在 C++ 中),
  2. 短变量成员(你能告诉我什么吗?m_v例如,意味着不阅读程序的其余部分?)
  3. 硬编码值(+ 48, + 11)
  4. (主观)混合有符号/无符号整数/字符(mingw/gcc 在编译时会惹恼你)。
  5. 代码复制粘贴(v /= 10和类似的 - C++ 有宏/模板,该死,所以如果你想手动展开循环,请使用它们!)。
  6. 不必要的多级 if/else。

除非您想在编程方面变得更糟,否则我建议避免尝试“理解”此代码片段。这是坏的。

我严重怀疑这种特殊的设计是分析的结果。最有可能的情况是一些“天才”认为他的代码片段将胜过内置函数。

当您想要性能时,您可以遵循以下模式:

  1. 编写初始版本。
  2. Repeat until performance gain is no longer worth it or until there's no solution:
    1. 不要对什么会提高性能做出太多假设。你是人类,人类的工作就是犯错误。根据墨菲定律,您的假设将是错误的。
    2. 首先考虑算法优化。
    3. 通过探查器运行代码。
    4. 找到瓶颈。
    5. 如果花在这个特定例程上的总时间减少到零,则调查总体性能增益。
    6. 如果收益合理(时间/成本),则优化例程。否则忽略。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

竞技编程中的快速输入/输出 的相关文章

随机推荐

  • 如何用JS以不可变的方式连接数组

    我想知道如何联系不可变的数组 让我们想象一下我从数组开始list 4 1 然后我从动作响应中接收数组 如下所示items 5 2 6 如何连接结果为的数组 4 1 5 2 6 并且该操作是不可改变的 Bonus 如何覆盖具有相同 id 的项
  • C++ std::string 是容器吗?

    对于你们中的一些人来说 这可能是一个简单的问题 但我想知道是否std string是一个容器 我所说的容器是指容器 例如std vector std list and std deque Since std basic string lt
  • 使用 Asyncio 进行非阻塞 Websocket 接收

    我正在开发一个 Python 3 程序 它试图做两件事 1 从外部 websocket 非阻塞 读取数据 类型 1 并且 2 在常规UDP套接字上接收数据 类型2 非阻塞 有很长一段时间 websocket 和 UDP 套接字上都没有数据
  • 以编程方式更新 Android 操作系统

    我正在从事一个移动设备管理项目 我们项目的要求之一是以编程方式更新 Android 设备操作系统 流程如下 服务器发送有关操作系统更新的推送通知 Android 客户端下载更新 现在我想以编程方式更新 Android 设备操作系统 我怎样才
  • 如何根据特定索引范围对 ArrayList 进行排序

    我的需要是根据特定的索引范围对字符串的 ArrayList 进行排序 例如 我的列表中有以下项目 abc xyz pqr asd 现在我想从索引 1 到最后一个索引对该列表进行排序 一种方式我认为我可以从具有所需索引范围的主列表创建一个子列
  • Delphi:检查文件是否正在使用

    我想写入 删除文件 但有时如果该文件正在被另一个程序使用 我会崩溃 如何检查文件是否被其他进程打开或者我可以打开它进行写入 问题是 在您检查是否可以获得独占访问权限和打开文件之间 其他东西获得了对该文件的独占访问权限 无论如何您都会收到异常
  • 如何分散客户使用 IE6 的注意力

    我们如何才能分散客户使用 IE6 的注意力 我们知道IE6并不是一个很好的符合标准的浏览器 有很多问题 如何满足客户不使用IE6 谢谢 我目前正在为我的公司建立一个新网站 我一直在考虑http code google com p ie6 u
  • Node.js:获取响应时间

    如何知道 URL 的响应时间 我在用着http get 发出 HTTP GET 请求 没有内置函数或值来获取响应时间 但您自己可以轻松获得该值 var http require http var start new Date http ge
  • Haskell 函数名中 ' 的含义?

    什么是报价 用于 我已经阅读了有关柯里化函数的内容 并阅读了定义 add 函数的两种方法 柯里化和非柯里化 咖喱版本 myadd Int gt Int gt Int myadd x y x y 但即使没有引号 它也同样有效 那么这有什么意义
  • appengine-mapreduce 达到内存限制

    我正在研究 appengine mapreduce 函数 并修改了演示以适应我的目的 基本上我有超过一百万行 格式如下 userid time1 time2 我的目的是找到每个用户 ID 的 time1 和 time2 之间的差异 但是 当
  • grep 最后一场比赛及其以下几行

    我已经学会了如何grep比赛前后的线路以及grep上一场比赛 但我还没找到如何做grep最后一场比赛及其下方的线条 该场景是服务器日志 我想列出命令的动态输出 该命令可能在一个服务器日志中使用多次 所以我想匹配将是命令并且以某种方式grep
  • HTML 范围滑块和 jQuery?

    我的网站中有以下代码 并使用 HTML5 集成了范围滑块 我希望滑块用值更新文本输入 反之亦然 我会使用 jQuery 来做到这一点吗 如果可以的话你能给我示例代码吗 Thanks
  • SELECT COUNT(*) 昂贵吗?

    您认为在每次页面加载时对一个非常大的表 例如 50K 行 中的条目进行计数是一个好主意吗 SELECT COUNT FROM table 现在我有大约 2000 行 看起来相当快 我没有看到页面加载有任何延迟 但表应该达到 50K 条目 我
  • 使用 wix 生成可执行文件

    我正在学习 Wix 我想生成 setup exe 文件而不是 setup msi 那可能吗 安装 EXE 通常称为引导程序 or chainer WiX 3 5 将附带一个名为burn exe 不幸的是 这仍在大力开发中 如果您只是想要一个
  • 验证AWS API网关的请求路径参数?

    假设我有一个带有路径的 api and pets and pets pet 现在我正在尝试验证路径 pets 参数 以便只有长度为 6 的字母数字字符的路径才会被验证并处理到后端 lambda 所有其他路径都将被拒绝 我尝试了以下 swag
  • 我可以使用 gmail 作为我网站的 smtp 服务器吗

    您好 我正在尝试建立并运行一个网站 它目前托管在 AWS 上 因此我目前没有运行自己的 smtp 服务器 所以在阅读了几篇文章后 我了解到我们可以使用gmail作为smtp服务器 我想仔细检查我读到的内容是否正确 我将使用智能求职板软件 我
  • 在C++ Win32中创建透明窗口

    我正在创建一个非常简单的 Win32 C 应用程序 其唯一目的是仅显示半透明的 PNG 窗口不应该有任何镶边 并且所有不透明度都应该在 PNG 本身中控制 我的问题是 当窗口下的内容发生变化时 窗口不会重新绘制 因此 PNG 的透明区域与应
  • 从互联网下载 SQLite 数据库并加载到 Android 应用程序中

    对于我的 Android 应用程序 我想使用一个大型数据库 大约 45 MB 一种解决方案是将 拆分的 数据库包含在资产文件夹中 并在第一次启动时将其复制到数据库目录 但这会消耗两次磁盘空间 一次在无法删除文件的资产文件夹中 一次在文件已复
  • 在DLL接口中使用boost::shared ptr可以吗?

    在 C 中开发一个返回 boost 共享指针并将其用作参数的 DLL 是否有效 那么 这样导出函数可以吗 1 boost shared ptr
  • 竞技编程中的快速输入/输出

    我在竞争性编程竞赛的解决方案中多次遇到过这个特定的代码片段 我了解此代码的基本用途来克服时间限制 但我想更深入地了解它 我知道 unistd h 可以访问系统调用包装函数 例如 fork pipe 和 I O 原语 读 写等 如果有人可以解