首页 > 其他分享 >modint 默认构造函数的一些想法

modint 默认构造函数的一些想法

时间:2024-07-24 19:50:33浏览次数:7  
标签:return const rhs 默认 operator modint mint 构造函数

今、在 zhengruioi.com 上参加模拟赛时被卡常了。这道题目涉及对 \(998244353\) 取模的操作,故我使用我自制的由 atcoder::static_modint 改写而来的 modint 完成了代码,这两个板子大致如下:

// modint
template <unsigned umod>
struct modint {/*{{{*/
  static constexpr int mod = umod;
  unsigned v;
  modint() : v(0) {}
  template <class T> modint(T x) : v(x % mod + (x < 0 ? mod : 0)) {}
  modint& operator+=(const modint& rhs) { v += rhs.v; if (v >= umod) v -= umod; return *this; }
  modint& operator-=(const modint& rhs) { v -= rhs.v; if (v >= umod) v += umod; return *this; }
  modint& operator*=(const modint& rhs) { v = static_cast<unsigned>(1ull * v * rhs.v % umod); return *this; }
  modint& operator/=(const modint& rhs) { assert(rhs.v); return *this *= qpow(rhs, mod - 2); }
  template <class T> friend modint qpow(modint a, T b) {
    modint r = 1;
    for (; b; b >>= 1, a *= a) if (b & 1) r *= a;
    return r;
  }
  friend int raw(const modint& self) { return static_cast<int>(self.v); }
  friend ostream& operator<<(ostream& os, const modint& self) { return os << raw(self); }
  friend modint operator+(modint lhs, const modint& rhs) { return lhs += rhs; }
  friend modint operator-(modint lhs, const modint& rhs) { return lhs -= rhs; }
  friend modint operator*(modint lhs, const modint& rhs) { return lhs *= rhs; }
  friend modint operator/(modint lhs, const modint& rhs) { return lhs /= rhs; }
};/*}}}*/
// atcoder::static_modint
template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

一开始,尝试将 modint 改为 long long,发现可以通过;unsigned long long 可以通过,且运行的比 long long 更快;但保留 modint,将 unsigned v 改为 unsigned long long v 时,发现内存超限。

为什么内存超限了?

发现 unsigned long long 版本,在本地 size 的结果大小为 1536077400B,而本题空间限制为 1G,当然会内存超限,但是为什么没发生这样的事情?

这时候想起,在这种评测机上,未使用的全局变量不会计入内存,也不会因为需要初始化他们而付出时间;但是我的 modint 有一个非平凡的默认构造函数:

modint() : v(0) {}

是否是这里的问题呢?

C++11 引入 = default 的函数体,考虑写为:

modint() = default;

即,使它的默认构造函数平凡。这样就不需要花费时间初始化它。

也就能够通过本题。

标签:return,const,rhs,默认,operator,modint,mint,构造函数
From: https://www.cnblogs.com/caijianhong/p/18321591

相关文章

  • venv 已激活,但 pip 安装仍然默认进行,并且 python 在源代码中看不到该库
    在终端shell中的vscode中输入“whichpython”显示默认路径:C:\Users\erjan\AppData\Local\Programs\Python\Python311\python.exe(my_venv)但是(my_venv)意味着我的venv处于活动状态,我做了pipinstalltransformers,但下面的代码仍然显示错误-无法看到......
  • Docker:无法在 docker 映像中使用 pythonnet 和 |无法创建默认的 .NET 运行时,该运行时
    我正在尝试使用clrfromPythonnet使用.DLL引用将一种文件类型转换为另一种文件类型。这就是我的代码的样子-importclrclr.AddReference(dll_path)importRxLibrary#ConverttoASCFormat-----------input_file=f"./{filename}.rxd"......
  • 意外的函数行为关键参数列表构造函数
    我已经将这个简单的代码简化为更大的python代码中的意外行为:deff(n,s=[]):s.append(n)returnsprint(f(3))print(f(5))给出的输出是:[3][3,5]我期望:[3][5]如果明确给出空列表作为参数,则f(5,s=[]),它按预期工作。我认为这是一个不好的做法,......
  • 如何使 argparse 与枚举和默认值完美配合?
    我有一个枚举:fromenumimportauto,EnumclassMyEnum(Enum):ONE=auto()TWO=auto()THREE=auto(),我想将它用作argparse的参数。更具体地说,我想创建一个接受枚举名称之一("one","two","three")并且可能具有默认值的参数,并且相......
  • WSL默认安装目录
    我当前在win11下进行以下操作,其它系统版本有问题可以留言一、安装WSL前提条件:我们需要保证你的操作系统版本满足**Windows10版本2004及更高版本(内部版本19041及更高版本)或Windows11**才能使用以下命令。启用适用于Linux的Windows子系统:打开powershell并输入d......
  • 在休息端点中验证查询字符串参数的默认方法是什么?
    我正在使用Python和Flask设计一个RESTAPI。我很好奇,如果有人输入无效的查询字符串参数,会发生什么?GEThttps://www.example.com/users?page=1;count=20;dummyinvalidparameter=dummyvalue例如,如果用户输入一个名为dummyinvalidparameter的查询参数怎么办......
  • idea maven 经常主目录自动变回默认的解决方法
    方法1:直接把默认C盘下的目录,替换为,或者添加阿里的settings.xml文件方法2:在IDEA右上角File->Settings->Build,Execution,Deployment->BuildTools->Maven我们可以看到自己的Maven配置信息如果不是自己配置的Maven,这样改修改C:\Users\lx\AppData\Roaming\JetBrains\I......
  • 修改Maven项目默认端口号最简单的方法
    前言每次在创建一个新的Maven项目之后,启动项目总会报8080端口号被占用的问题,既然每次都有这样的困扰,那不如一了百了,直接修改默认的8080端口号。(如果还是想要默认端口号。可参考我主页文章杀死占用了8080的进程)问题描述下面给大家看一下我的运行错误日志:端口修改步骤 1.......
  • gitlab安装与修改默认端口,并设置开机自启(保姆教程)
    第一步安装,首先下载rpm安装包,我下载的版本是gitlab-ce-16.8.8-ce.0.el7.x86_64.rpm,下载地址为:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-16.8.8-ce.0.el7.x86_64.rpm 第二步在/usr/local文件夹下创建一个gitlab文件夹,将下载的包放进去,如下图: ......
  • 为什么conda环境总是默认在C盘以及如何修改安装路径|conda环境的安装路径问题
    通过conda配置新的虚拟环境的时候,明明Anaconda的默认路径不在C盘,可最后新建的虚拟环境还是会配置在C盘这里找不到图片了,用下我之前的图片就是这个虚拟环境就只会建在C:\Users\用户名\.conda\envs这个路径下先说原因:路径问题,在.conda的配置文件中没有指明默认路径或者是......