关于取模与Mint模板
一、关于取模运算
1.1 关于本篇内容
在做题的时候总会遇到很多需要取模的结果,让答案对取
1.2 关于常见的取模等价形式
1.3 为什么在减法运算和除法运算中要考虑加法逆元于乘法逆元
在我们做运算的是免不了用除法、减法来进行公式的运算。比如说以下情况
对于上面这个式子来说,这么运算是完全没有任何问题的。但是当我们数大了以后就会根据上文所述的等价形式进行类比推理取模,比如
但是我们会发现,在进行取模后,由于
同理在我们,减法中,也常会用加法逆元来实现。避免负数的出现,比如下面的例子
我们会发现明显出现了负数的情况,所以我们为了避免溢出、出负数、除
1.4 加法逆元
我们加法逆元可以直接通过以下公式来转换,因为对于一个整数的逆元可以通过以下公式实现
这样不仅可以避免溢出,也可以避免减法产生的负数存在。
1.5 乘法逆元
若存在整数
这里等于乘3,就是因为3是2的模5乘法逆元。
所以对于乘法而言,我们就会将触发转发为乘法逆元来避免除0。
二、关于乘法逆元求法
大家根据1.4
很容易就可以得出加法逆元的修改方式,就是把减法改为上述的式子。那么对于乘法逆元来说,我们应该如何求呢?
这里我们会用到一个定理,即费马小定理:如果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自动取模
上述方法可以通过逆元的方式来解决掉我们大数减法、除法的负数、除 Mint
自动取模,重载一下就可以自动模
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>;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具