trick : Trygub num

这篇具有很好参考价值的文章主要介绍了trick : Trygub num。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

trick大意

我对于这个trick的理解为:支持位运算的高精度
维护一个以 \(b\)为基数的大数 \(N\),并支持以下功能:

  • 给定(可能是负)整数 \(|x|, |y| \leqslant n\),将 \(x b^y\)加到 \(N\)
  • \(N \geqslant 0\)时,给定\(k\),打印\(N\)的第\(k\)位数字(指以\(b\)为基底意义下的)。
  • 检查\(N\)是正值、负值还是等于\(0\)

操作 \(O(\log n)\)均摊时间复杂度和 \(O(q)\)内存。并且只需要map进行实现,相比于线段树等数据结构维护非常的好写。

例题及实现 : [NOI2017] 整数

题意简述 : 一个整数\(x\),进行\(n\)次操作,分为两种:

  • \(x\) 加上整数 \(a\cdot 2^b\),其中 \(a\) 为一个整数,\(b\) 为一个非负整数

  • 询问 \(x\) 在用二进制表示时,位权为 \(2^k\) 的位的值(即这一位上的 \(1\) 代表 \(2^k\)

保证在任何时候,\(x\geqslant 0\)

  • 对于所有测试点,满足 \(|a| \leqslant 10^9\)
  • 对于所有测试点,满足 \(0 \leqslant b, k \leqslant 30n\)
  • 对于所有测试点,满足 \(n \leqslant 1000000\)

这里我们的基底为\(2^{30}\),感性理解一下:把\(x\)的二进制表示分为若干段,每一段长是\(30\)位,这样每次我们只需要改动最多两段,分别对这两段将原数字位运算为相应位后直接加到数中,多于\(2 ^ {31}\)的进行进位操作,发现其实很像一个\(2^{30}\)进位制,这也是以\(b\)为基底的真正含义。

如果仅有加法的话,时间复杂度均摊是\(O(\log n)\)的。

但是因为我们有减法操作,会在时间复杂度上出现一些问题,如果存在这样一段\(\left[2^{30} - 1, 2^{30} - 1, 2^{30} - 1...\right]\),对应实际数的二进制位全为 1 。然后有这样一段操作,\(\left\{+1, -1, +1, -1, +1...\right\}\),也就是说,会不断的进行进位,借位,进位,借位操作,会花费大量的时间。

该trick的应对方法是,将每一块的取值范围由\(\left[0,+base\right)\)转换为\(\left(-base, +base\right)\),即平衡\(base\)进制 (类比平衡三进制)。

也就是说,只有当大于 \(base\) 或小于 -base。

为什么会想到这样呢,像加法一样,减法其实不需要一为负数就借位,因为不管低位是负的多少,只要绝对值不大于 \(base\) ,只需要借高位的一个,就能把它回满,因此当绝对值大于 \(base\) 时,才进行进位或借,这样均摊复杂度也是\(O(\log n)\)的,而当询问的时侯,才对不满 \(base\) 的借位进行处理。

关于均摊时间复杂度

其实我不是很能证明,但是再次感性理解,就是假设一些段内的数为\([2^{30} - 1,2^{30} - 1,2^{30} - 1,2^{30} - 1...]\) 即对应二进制内全为\(1\)
显然加一次,他就会往后进很多位花大量时间,虽然这一次花了很多时间,但是呢,需要进位的次数其实是很少的,而不需要进位的时候,直接加又很快,这样下来我们的均摊时间就不是那么慢了。

  • 具体证明看这里

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll n, t1, t2, t3;

struct Num
{
    const ll base = 1 << 30;
    map<ll,ll> num;
    
    void add(ll a, ll b)
    {
        num[b] += a;
        ll t;
        do
        {
            t = num[b] / base;
            num[b + 1] += t;//进位操作
            num[b] -= t * base;
            if(num[b] == 0)
                num.erase(b);//只关心有数值的数,因此若为0则删去
            b++;
        } while(t);
        if(num[b] == 0)
            num.erase(b);
    }
    
    ll get(ll k)
    {
        auto to = num.lower_bound(k);
        ll res = (to == num.end() || to->first > k) ? 0 : to->second;//若这一位为空,先设为0
        
        if(to != num.end() && prev(to)->second < 0)//若存在比k高的位,并且比k低的位上有负数,则需要借位
            res--;
        return (res + base) % base;//这一步,如果res是负数,则需要向前借位,如果是正数,取模后无影响
    }
} s;

int main()
{
    cin >> n >> t1 >> t2 >> t3;
    while(n--)
    {
        int flag;
        cin >> flag;
        if(flag == 1)
        {
            ll a, b;
            cin >> a >> b;
            s.add(a * (1ll << (b % 30)), b / 30);//在b/30块加a * (1ll << (b % 30))
        }
        else 
        {
            ll k;
            cin >> k;
            cout << ((s.get(k / 30) >> (k % 30)) & 1ll) << "\n";//get得到k/30块内实际的数
        }
    }
    
    
    return 0;
}

习题

  • [NOI2017] 整数

  • 1817E - Half-sum

  • 1810F - M tree

  • 102354E -Decimal Expansion

参考资料

如果英语还不错,可以直接看原CF博客:
Big integers with negative digits: The Trygub numbers

CF原作者的[NOI2017] 整数提交记录文章来源地址https://www.toymoban.com/news/detail-627012.html

到了这里,关于trick : Trygub num的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 对于装饰器模式与代理模式的个人理解

    对于这两个十分接近的设计模式,确实容易产生困惑,代理模式和装饰器模式看起来十分相似,都是由两个类实现相同的接口,然后一个类套另一个类。这件事足足困扰了我5分钟之久,在此总结一下它们的差别。 装饰器模式相当于主动可选的代理模式,是对原本功能的拓展

    2024年02月16日
    浏览(23)
  • 对于<router-view>标签的理解

    router-view的含义: router-view: 路由容器 Vue 路由中的 router-view 是用来承载当前级别下的子级路由的一个视图标签; 此标签的作用就是显示当前路由级别下一级的页面。 router-view的作用: 就比如说App.vue是根组件,在它的template标签里使用router-view,而且配置好路由的情况下,就

    2024年01月17日
    浏览(29)
  • 我这些年对于自动化测试的理解

    把以人为驱动的测试行为转化为机器执行的一种过程。 简单讲:比如使用自动化测试框架、脚本、工具等自动打开测试对象(引用),自动去执行测试用例(此过程中包含自动化查找元素、控件等),自动输入测试数据、自动生成测试报告等一系列的自动化过程; 通俗讲:

    2024年02月05日
    浏览(33)
  • 对于LayoutInflater.from(this).inflate()方法的理解

    对于 LayoutInflater.from(this).inflate() 方法的几个参数以及用法总是迷迷糊糊,源码看了忘,忘了看,因此决定写这篇博客做下记录。 我们知道,调用LayoutInflater.from(this).inflate()方法最终都会走三参的方法 public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) ,这

    2024年02月13日
    浏览(31)
  • 对于params、data、headers传参的基础理解

    提示:简单的理解, 传参给后台有三种方式: 1. params 传参 2. data 传参 3. headers 传参 params 的对象参数名和值, axios 源码会把参数和值,拼接在 url? 后面给后台(query 查询字符串) 代码如下:前台 data 的对象参数名和值,axios 源码会把参数和值,拼接在请求体里(body 参数)

    2024年02月06日
    浏览(33)
  • 对于EVM系链交易缓冲池txpool的理解

    区块链就是和交易打交道,我们今天就介绍下,交易处理过程中的一个重要组成部分:txpool。这篇文章主要从功能角度介绍,通过这篇文章会了解: txpool的在交易中的位置和作用。 txpool的功能,核心组成部分queued和pending。 txpool如何实现它的功能。 txpool源码的重要关注点。

    2024年02月05日
    浏览(27)
  • NXP对于Ethercat部署与支持(主站篇IGH与SOEM)

    EtherCAT的主站开发是基于EtherCAT 控制系统的开发中非常重要的环节。目前常见开源的主站代码为的RT-LAB开发的SOEM (Simple OpenSource EtherCAT Master)和EtherLab的the IgH EtherCAT® Master。使用起来SOEM的简单一些,而the IgH EtherCAT® Master更复杂一些,但对EtherCAT的实现更为完整。 具体比较如下

    2024年02月15日
    浏览(26)
  • 什么是 AOP?对于 Spring IoC 和 AOP 的理解?

    AOP(Aspect-Oriented Programming) ,即 面向切面编程, 它与 OOP( ObjectOriented Programming, 面向对象编程) 相辅相成,提供了与OOP 不同的抽象软件结构的视角 在 OOP 中, 我们以 类(class) 作为我们的基本单元 而 AOP 中的基本单元是 Aspect(切面) IOC(Inverse of Control:控制反转) 是一种设计思想,

    2024年02月12日
    浏览(34)
  • 微信小程序只支持https请求,如何解决对于一些接口是http请求的?

    微信小程序支持使用 wx.request() 发起 HTTPS 网络请求。 如果后台接口是 HTTP 协议,则需要您在服务端做一个转发,将 HTTPS 请求转发到 HTTP 接口上。这样,就可以在微信小程序中使用 HTTPS 协议访问 HTTP 接口了。 例如,可以在服务端使用 Node.js 做一个简单的转发: 然后,在微信

    2024年02月12日
    浏览(35)
  • 刚入职因为粗心大意,把事情办砸了,十分后悔

    刚入职,就踩大坑,相信有很多朋友有我类似的经历。 5年前,我入职一家在线教育公司,新的公司福利非常好,各种零食随便吃,据说还能正点下班,一切都超出我的期望,“可算让我找着神仙公司了”,我的心里一阵窃喜。 在熟悉环境之后,我趁着上厕所的时候,顺便去

    2024年02月05日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包