取模数模板类 modInt<mod>
,以常量模数 mod
为模板构造。
可类似正常数字一样进行加减乘除四则运算。特别地,四则运算中的除法采用的是乘法逆元。
将下述代码复制于文件 modint.hpp
中,并和代码文件放在同一文件夹下,在自己的代码中直接写 #include “modint.hpp”
即可使用 modInt<mod>
类,不需要和其他 .cpp
联合编译、链接。
#include <iostream>
#ifndef MOD_INT
#define MOD_INT
template <const long long mod>
class modInt{ // 有模数
public:
modInt(const long long x=0): // 由数字构造,可隐式进行
num(x%mod){}
explicit operator long long() // 转换回数字,必须显式进行
{
return num;
}
friend std::ostream& operator<< (std::ostream& out, const modInt& item) // 重载 C++ 标准输出
{
out << item.num << std::endl;
return out;
}
static modInt fastPow(modInt a, long long b) // 快速幂,静态函数
{
modInt res(1);
for( ; b; a = a*a, b >>= 1)
if(b&1)
res = res * a;
return res;
}
static modInt inv(const modInt x) // 费马小定理乘法逆元,静态函数,没有加安全措施,请使用者注意 mod 要是质数
{
return fastPow(x, mod-2);
}
friend modInt operator+ (const modInt& lhs, const modInt& rhs) // 重载加法
{
return (lhs.num + rhs.num) % mod;
}
modInt& operator+= (const modInt& ano)
{
num = (num + ano.num) % mod;
return *this;
}
friend modInt operator* (const modInt& lhs, const modInt& rhs) // 重载乘法
{
return lhs.num * rhs.num % mod;
}
modInt& operator*= (const modInt& ano)
{
num = num * ano.num % mod;
return *this;
}
friend modInt operator- (const modInt& lhs, const modInt& rhs) // 重载减法
{
long long tmp = lhs.num-rhs.num;
return tmp<0 ? tmp+mod : tmp;
}
modInt& operator-= (const modInt& ano)
{
*this = *this - ano;
return *this;
}
friend modInt operator/ (const modInt& lhs, const modInt& rhs) // 重载除法,注意要保证 rhs 有逆元存在(下取整除法请转换回数字进行)
{
return (lhs*inv(rhs)).num % mod;
}
modInt& operator/= (const modInt& ano)
{
*this = *this / ano;
return *this;
}
private:
long long num;
};
#endif
需要注意的是,本文设计的模数类并不适用于输入的模数。原因是,模板类需要在编译期间就明确下来,而自定义的模数需要在运行后才会输入。
应用实例:洛谷P8106 数学练习
题目和算法不加以细讲,请读者自行读题、思考和查看题解。仅展示模板类使用方式:
#include <iostream>
#include "modint.hpp"
using namespace std;
typedef long long LL;
const LL mod = 998244353;
typedef modInt<mod> mint;
mint fastPow(mint a, LL b)
{
mint res(1);
for(; b; b>>=1, a = a * a)
if(b&1) res = res * a;
return res;
}
const int maxn = 1000001;
mint fac[maxn], invfac[maxn];
int main(){
int n;
cin >> n;
fac[0] = 1;
for(int i=1; i<=n; i++)
fac[i] = fac[i-1] * i;
invfac[n] = mint(1)/fac[n];
for(int i=n-1; i>=0; i--)
invfac[i] = invfac[i+1] * (i+1);
auto C=[](int n, int m) -> mint{
return fac[n] * invfac[m] * invfac[n-m];
};
mint ans(0);
for(int i=1; i<n; i++)
ans=ans+C(n-2, i-1);
if(n%2 == 0)
ans=ans-C(n-2, (n-2)>>1);
cout << ans << endl;
return 0;
}
题目的测试点都可以通过。可以看到代码中不再出现大量的显示的取模运算以及“层岩叠嶂”的括号。
题目上交代码时一般只允许交一篇代码文件。关于此,读者只需要把 modint.hpp
中的 template < const long long mod > class modInt
的定义(实现)粘贴在自己的代码中即可。
如果代码中有错误或者不高明的地方,希望各位读者多多指正!