首页 > 其他分享 >关于取模与Mint模板

关于取模与Mint模板

时间:2024-11-07 21:31:32浏览次数:1  
标签:取模 return Mint rhs constexpr 逆元 res MInt 模板

一、关于取模运算

1.1 关于本篇内容

在做题的时候总会遇到很多需要取模的结果,让答案对取 \(1e9 + 7\) 或者是 \(998244353\) 这样的数字取模。这两个数都是质数!我们这篇主要是要说明为什么取模的时候对于除法、减法需要考虑逆元。以及对于逆元应该如何实现。

1.2 关于常见的取模等价形式

  • $(a * b) % p = (a % p * b) % p $

  • \((a + b)\% = (a \%p + b)\%p\)

  • \((a + b) \% p = (a \% p + b \% p) \% p\)

  • $(a * b) % p = (a % p * b%p) % p $

  • \((a - b)\% p = (a \% p - b \% p) \% p\)

1.3 为什么在减法运算和除法运算中要考虑加法逆元于乘法逆元

在我们做运算的是免不了用除法、减法来进行公式的运算。比如说以下情况

\[21/7\%5=3 \]

对于上面这个式子来说,这么运算是完全没有任何问题的。但是当我们数大了以后就会根据上文所述的等价形式进行类比推理取模,比如

\[21\%5/7\%5=0 \]

但是我们会发现,在进行取模后,由于\(21\%5=1\)会导致计算出的结果出问题了。

同理在我们,减法中,也常会用加法逆元来实现。避免负数的出现,比如下面的例子

\[(37 - 5)\%7=4\\ \]

\[(37 \% 7 - 5\%7)= (2-5)=-3 \]

我们会发现明显出现了负数的情况,所以我们为了避免溢出、出负数、除 \(0\) 的情况我们将采用加法逆元、乘法逆元的方式来进行计算。

1.4 加法逆元

我们加法逆元可以直接通过以下公式来转换,因为对于一个整数的逆元可以通过以下公式实现

\[(a - b)\%p=(a\%p + (p - b\%p))\%p \]

这样不仅可以避免溢出,也可以避免减法产生的负数存在。

\[a\% p\geq0\\ \]

\[b\%p\lt p\\ \]

\[综上可得:a\%p + (p - b\%p) \ge0\\ \]

\[(37\%7) + (7 - 5 \%7) = (2 + 2) = 4 \]

1.5 乘法逆元

若存在整数 \(b,m\),且两数互质,并且对于任意的整数 \(a\) ,若满足 \(b|a\),则存在一个整数 \(x\),使得 \(\frac{a}{b} \equiv a \times x(modx)\) ,则成 \(x\) 为 \(b\)的模 \(m\)的乘法逆元。

\[(6 / 2)\%5\equiv(6*3)\%5 \\ \]

这里等于乘3,就是因为3是2的模5乘法逆元。

\[2 \times3\equiv1(mod5) \]

所以对于乘法而言,我们就会将触发转发为乘法逆元来避免除0。

二、关于乘法逆元求法

大家根据1.4很容易就可以得出加法逆元的修改方式,就是把减法改为上述的式子。那么对于乘法逆元来说,我们应该如何求呢?

这里我们会用到一个定理,即费马小定理:如果p是一个质数,而整数 \(a\) 不是 \(p\) 的倍数,则有 \(a^{(p-1)}≡1(mod p)\)

那么我们先把定理放这里,我们先从乘法逆元的概念上来想下,要如何求乘法逆元。

对于求某个数的乘法逆元 \(\frac{a}{b} \equiv a \times x(modx)\) 那么在这个式子里面,\(x\) 就是 \(b\) 的乘法逆元,我们要求的就是 \(x\),那么式子其实可以通过约分化简得到,最后目标转化成了 \(b\times x\equiv1(mod m)\) 找这个 \(x\) 是多少,那么我们由于一般题面里面取模的 \(m\) 都是质数,所以这个条件会满足,我们就可以看到上文的费马小定理

\[a^{(p-1)}≡1(mod p)\\ b\times b^{p-2}\equiv1(modp) \]

所以我们发现只要求出来\(b^{p-2}\%p\)即可,那么这个问题就直接转换成了一个快速幂了,所以我们直接用快速幂的板子来求逆元即可。

ll qmi(ll a, ll b, ll p)
{
	ll res = 1;
	while(b)
	{
		if(b & 1) res = res * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return res;
}

void solve()
{
	ll a, b, p;
	std::cin >> a  >> p;
	std::cout << qmi(a, p - 2, p) << endl;	// 这个就是求出来a模p的逆元
	return;
}

三、Mint自动取模

上述方法可以通过逆元的方式来解决掉我们大数减法、除法的负数、除 \(0\)问题。但是在写代码的时候会发现产生大量的 \(mod\)运算,括号带了一个又一个。很不美丽,我们就可以用Mint自动取模,重载一下就可以自动模\(P\)相当优美

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

template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(LL 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) {
        LL 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 = 1000000007;
using Z = MInt<P>;

标签:取模,return,Mint,rhs,constexpr,逆元,res,MInt,模板
From: https://www.cnblogs.com/wxzcch/p/18534043

相关文章

  • 逆向 | linux c父子进程通信模板
    逆向|linuxc父子进程通信模板#include<stdio.h>#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdlib.h>#include<errno.h>intmain(){pid_tpid;//parent_idpid_tcid;......
  • blockchain | web3.py交互模板
    blockchain|web3.py交互模板exp:fromweb3importWeb3fromweb3.middlewareimportSignAndSendRawMiddlewareBuilderimportjsonw3=Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))ifnotw3.is_connected(): print('connerr') exit(-1)......
  • C++ 在模板三个阶段检查错误
    第一个阶段是编译模板本身时。在这个阶段,编译器通常不会发现很多错误。编译器可以检查语法错误,例如忘记分号或者变量名拼错等,但也就这么多了。第二个阶段是编译器遇到模板使用时。在此阶段,编译器仍然没有很多可检查的。对于函数模板调用,编译器通常会检查实参数目是否正确。它还能......
  • 「C/C++」C++标准库 之 #include<functional> 函数模板库
    ✨博客主页何曾参静谧的博客......
  • PbootCMS 模板修改 tags 实现 keywords 内容关联匹配
    修改ParserController.php文件:打开 apps/home/controller/ParserController.php 文件,找到以下代码://tags数据参数筛选$where2=array();if($tags){$tags_arr=explode(',',$tags);foreach($tags_arras$value){if($value){if($fuzzy)......
  • 织梦网站模板 修改logo,织梦模板Logo修改方法
    在织梦CMS中修改模板的Logo可以通过以下步骤完成:登录后台:打开织梦CMS的后台管理页面,输入用户名和密码登录。找到模板文件:在后台左侧菜单中,点击“模板”>“默认模板管理”。选择需要修改的模板,点击“编辑”。修改HTML文件:找到显示Logo的HTML代码,通常在头部文件......
  • 整数取模类
    实现一个整数取模类(加减乘除均可)。template<intMod,typenameT=int>classModInteger{private: Tx;//数值本身,类型默认为intprivate: staticTincrease(constT&num){returnnum>=Mod?num-Mod:num;} staticTdecrease(constT&num){returnnum&l......
  • P4149 [IOI2011] Race——点分治 模板
    [IOI2011]Race题目描述给一棵树,每条边有权。求一条简单路径,权值和等于\(k\),且边的数量最小。输入格式第一行包含两个整数\(n,k\),表示树的大小与要求找到的路径的边权和。接下来\(n-1\)行,每行三个整数\(u_i,v_i,w_i\),代表有一条连接\(u_i\)与\(v_i\),边权为\(w_i\)......
  • 什么是C++模板,有哪些类型的模板?
    模板C++模板是一种强大的语言特性,允许开发者编写与类型无关的代码,从而实现代码的复用和灵活性。通过模板,可以定义函数和类,具体实现将由具体的类型实例化决定。函数模板函数模板(FunctionTemplates):函数模板用于定义一个通用的函数,该函数可以接受任意类型的参数。通过使用模......
  • EasyQBlog .NET 8 + Q-Blog 2.0博客模板 + easyweb iframe后台模板 开发的个人博客
    EasyAdmin介绍.NET8+Q-Blog2.0博客模板+easywebiframe后台模板开发的个人博客演示地址:https://www.baocaige.top暂不开源,需要滴滴!!!项目截图 ......