数论是信奥赛中的“送分题”,只要掌握了基础,就能轻松拿分。
很多孩子觉得数论难,其实就那么几个知识点。今天,我整理质数判断、约数计算、最大公约数等常用数论知识,附代码模板,让孩子不再丢分。
// 判断单个质数 O(√n)
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
// 筛法求1..n的所有质数 O(n log log n)
const int N = 1000000;
bool isPrime[N+1];
vector<int> primes;
void sieve() {
memset(isPrime, true, sizeof(isPrime));
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= N; i++) {
if (isPrime[i]) {
primes.push_back(i);
for (int j = i * 2; j <= N; j += i)
isPrime[j] = false;
}
}
}
// 欧几里得算法 O(log n)
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// 最小公倍数 LCM
int lcm(int a, int b) {
return a / gcd(a, b) * b; // 先除后乘,防止溢出
}
// 求解 ax + by = gcd(a,b) 的一组解
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1; y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
应用:求解同余方程、模逆元。
// 求所有约数 O(√n)
vector<int> getDivisors(int n) {
vector<int> res;
for (int i = 1; i * i <= n; i++) {
if (n % i == 0) {
res.push_back(i);
if (i != n / i) res.push_back(n / i);
}
}
return res;
}
// 约数个数定理
int countDivisors(int n) {
int cnt = 1;
for (int p : primes) {
if (p * p > n) break;
int power = 0;
while (n % p == 0) {
n /= p;
power++;
}
cnt *= (power + 1);
}
if (n > 1) cnt *= 2;
return cnt;
}
// 计算 a^b % mod O(log b)
long long qpow(long long a, long long b, long long mod) {
long long res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
应用:大数幂运算、模逆元计算。
学员小然的经历:“以前遇到数论题直接跳过,觉得太难了。后来薛老师把这几个模板给我,让我背熟。下次考试遇到一道求最大公约数的题,我直接套模板,3分钟就做出来了。原来数论题是送分题!”
数论不可怕,可怕的是不敢学。
这5个模板背熟,数论题轻松拿分。
📞 想获取《数论模板大全》?可添加薛老师微信免费领取。