c++专题四学习日记
1.整除
存在整数k使得a=b*k;称为b整除a,记作b|a
2.同余
如果a-b=km (k∈Z),则a与b模m同余,记作a≡b(mod m)
(a mod b :a%b
3. GCD最大公约数
辗转相除法(欧几里得算法):
若
$$
a=b*q+r(0≤r<b)
$$
则
$$
gcd(a,b)=gcd(b,r)
$$
代码实现gcd:
int gcd(int a,int b){while(b!=0){int r=a%b;a=b;b=r;}return a;
}
裴蜀定理(Bezout's Identity):
对于任意整数 和 ,存在整数 和 使得
$$
ax+by=gcd(a,b)
$$
扩展欧几里得算法(exgcd):
同时求gcd(a,b)和一组整数x,y.
// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{if (!b){x = 1; y = 0;return a; //到达递归边界开始向上一层返回}int d = exgcd(b, a % b, x, y);int temp=y; //推出这一层的x,yy=x-(a/b)*y;x=temp;return d;
}
//当上一层的解是x1,y1,则bx1 + (a%b)y1 = gcd(a,b)
--->bx1+(a-(a/b)b)*y1 = gcd(a,b)
--->ay1+ b(x1-(a/b)*y1) = gcd(a,b)
则下一层的x,y:x=y1 ; y= x1-(a/b)*y1
求乘法逆元:
1.用exgcd
求a的乘法逆元x使得ax≡1(mod m)(前提gcd(a,m)=1
//exgcd返回g,x,y
#include <tuple>
// 扩展欧⼏⾥得算法:返回 (g, x, y),满⾜
// x * a + y * b = g = gcd(a, b)
std::tuple<long long, long long, long long> extendedGCD(long long a, long long b) {
if (b == 0)
return {a, 1, 0};
auto [g, x1, y1] = extendedGCD(b, a % b);
long long x = y1;
long long y = x1 - (a / b) * y1;
return {g, x, y};
}// 计算 a 关于模 m 的乘法逆元,若不存在则返回 -1
long long modInverse(long long a, long long m) {
auto [g, x, y] = extendedGCD(a, m);
if (g != 1) {
// a 与 m 不互质,逆元不存在
return -1;}
// 保证 x 为正
x %= m;
if (x < 0)
x += m;
return x;
}
2.快速幂(基于费马小定理
费马小定理:当模m是质数时:
$$
a^{m-1}≡1(mod m)
$$
所以:
$$
a{m-2}≡a(mod m)
$$
// 快速幂计算:计算 a^b mod mod
long long modExp(long long a, long long b, long long mod) {long long res = 1;a %= mod;while (b > 0) {if (b & 1)res = (res * a) % mod;a = (a * a) % mod;b >>= 1;}return res;
}
// 计算 a 关于模 m 的乘法逆元(m 为质数)
long long modInverseFast(long long a, long long m) {// 根据费⻢⼩定理,a^(m-2) mod m 即为 a 的逆元return modExp(a, m - 2, m);
}
埃式筛
bool st[N];//存合数
vector<int> pr;
void init(){for(int i=2;i<N;i++){if(!st[i]) pr.push_back(i);for(auto zz:pr){if(zz*i>=N)break;st[zz*i]=true;if(i%zz==0)break;}}
}
线性筛
#include <vector>
using namespace std;
class LinearSieve {
public:// 筛选出的素数列表vector<int> primes;// 标记数组:isComposite[i] 为 true 表示 i 是合数(⾮素数)vector<bool> isComposite;// 构造函数:筛选 2 到 n 范围内的所有素数LinearSieve(int n) {isComposite.assign(n + 1, false);// 从 2 开始筛for (int i = 2; i <= n; i++) {if (!isComposite[i]) {primes.push_back(i);}for (int p : primes) {if (i * p > n)break;isComposite[i * p] = true;if (i % p == 0)break;}}}
};