数论算法的一些模板
数论
质数
哥德巴赫猜想
哥德巴赫猜想的内容如下:
任意一个大于 4 的偶数都可以拆成两个奇素数之和。
例如:
8=3+5
20=3+17=7+13
42=5+37=11+31=13+29=19+23
现在,你的任务是验证所有小于一百万的偶数能否满足哥德巴赫猜想。
6≤n<106
#include <iostream>
using namespace std;
const int N = 1000010;
int prime[N], cnt;
bool st[N];
void init(int n) {
for (int i = 2; i <= n; ++i) {
if (!st[i]) prime[++cnt] = i;
for (int j = 1; prime[j] <= n / i; ++j) {
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
int main(void) {
init(N - 1);
int n;
while (cin >> n, n) {
for (int i = 1; ; ++i) {
int x = prime[i], y = n - x;
if (!st[y]) {
printf("%d = %d + %d\n", n, x, y);
break;
}
}
}
return 0;
}
质数距离
给定两个整数 L 和 U,你需要在闭区间 [L,U] 内找到距离最接近的两个相邻质数 C1 和 C2(即 C2−C1 是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。
同时,你还需要找到距离最远的两个相邻质数 D1 和 D2(即 D1−D2 是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。
1≤L<U≤2^31−1
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 1000010;
int prime[N], cnt;
bool st[N];
int init(int n) {
memset(st, false, sizeof st);
for (int i = 2; i <= n; ++i) {
if (!st[i]) prime[++cnt] = i;
for (int j = 1; prime[j] <= n / i; ++j) {
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
signed main(void) {
int l, r;
while (cin >> l >> r) {
init (50000);
memset(st, false, sizeof st);
for (int i = 1; i <= cnt; ++i) {
LL p = prime[i];
for (LL j = max(p * 2, (l + p - 1) / p * p); j <= r; j += p) {
st[j - l] = true;
}
}
cnt = 0;
for (int i = 0; i <= r - l; ++i) {
if (!st[i] && i + l >= 2)
prime[++cnt] = i + l;
}
if (cnt < 2) {
puts("There are no adjacent primes.");
continue;
}
int a = 1, b = 1;
for (int i = 1; i + 1 <= cnt; ++i) {
int d = prime[i + 1] - prime[i];
if (d < prime[a + 1] - prime[a]) a = i;
if (d > prime[b + 1] - prime[b]) b = i;
}
printf("%d,%d are closest, %d,%d are most distant.\n",
prime[a], prime[a + 1], prime[b], prime[b + 1]);
}
}
分解质因数
将n分解质因数,输出底数和指数
void solve() {
int n;
cin >> n;
for (int i = 2; i <= n / i; ++i) {
if (n % i == 0) {
int s = 0;
while (n % i == 0) n /= i, s++;
cout << i << ' ' << s << endl;
}
}
if (n > 1) cout << n << ' ' << 1 << endl;
}
阶乘分解
给定整数 N,试把阶乘 N! 分解质因数,按照算术基本定理的形式输出分解结果中的 pi 和 ci 即可。
#include <iostream>
using namespace std;
const int N = 1000010;
int prime[N], cnt;
bool st[N];
int n;
void init(int n)
{
for (int i = 2; i <= n; ++i) {
if (!st[i]) prime[++cnt] = i;
for (int j = 1; prime[j] <= n / i; ++j) {
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
int main(void)
{
int n;
cin >> n;
init(n);
for (int i = 1; i <= cnt; ++i) {
int p = prime[i];
int s = 0;
for (int j = n; j; j /= p) {
s += j / p;
}
cout << p << ' ' << s <<endl;
}
return 0;
}
约数
约数个数
输入n个正整数,求他们成绩的约数个数
(s1+1)*(s2+1)*...*(sn+1)
#include <iostream>
#include <unordered_map>
using namespace std;
const int MOD = 1e9 + 7;
int main(void) {
int n;
cin >> n;
unordered_map<int, int> mp;
while (n--) {
int x;
cin >> x;
for (int i = 2; i <= x / i; ++i) {
if (x % i == 0) {
int s = 0;
while (x % i == 0) x /= i, s++;
mp[i] += s;
}
}
if (x > 1) mp[x] += 1;
}
//LL
int res = 1;
for (auto it : mp) {
int s = it.second;
res = (long long)res * (s + 1) % MOD;
}
cout << res;
return 0;
}
约数之和
输入n个数,求它们乘积的约数之和
(p^0+p^1+...+p^k)*()...*()
#include <iostream>
#include <unordered_map>
using namespace std;
const int MOD = 1e9 + 7;
typedef long long LL;
int main(void) {
int n;
cin >> n;
unordered_map<int, int> mp;
while (n--) {
int x;
cin >> x;
for (int i = 2; i <= x / i; ++i) {
if (x % i == 0) {
int s = 0;
while (x % i == 0) x /= i, s++;
mp[i] += s;
}
}
if (x > 1) mp[x] += 1;
}
int res = 1;
for (auto e : mp) {
int p = e.first, s = e.second;
int t = 1;
while (s--) {
t = ((LL)t * p + 1l) % MOD;
}
res = (LL) res * t % MOD;
}
cout << res;
return 0;
}
反素数
对于任何正整数 x,其约数的个数记作 g(x),例如 g(1)=1、g(6)=4。
如果某个正整数 x 满足:对于任意的小于 x 的正整数 i,都有 g(x)>g(i),则称 x 为反素数。
例如,整数 1,2,4,6 等都是反素数。
现在给定一个数 N,请求出不超过 N 的最大的反素数。
1≤N≤2∗10^9
#include <iostream>
using namespace std;
int prime[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
int maxv, number;
int n;
void dfs(int u, int last, int p, int s)
{
if (s > maxv || s == maxv && p < number) {
number = p;
maxv = s;
}
if (u == 9) return;
for (int i = 1; i <= last; ++i) {
if ((long long) p * prime[u] > n) break;
p *= prime[u];
dfs(u + 1, i, p, s * (i + 1));
}
}
int main(void)
{
cin >> n;
dfs(0, 30, 1, 1);
cout << number;
return 0;
}
欧拉函数
欧拉函数
1~n中与n互质的数的个数
void solve(int n) {
int res = n;
for (int i = 2; i <= n / i; ++i)
if (n % i == 0) {
res = res / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) res = res / n * (n - 1);
cout << res << endl;
}
欧拉筛
const int N = 1000010;
int prime[N], cnt, phi[N];
bool st[N];
void get_phi(int n) {
phi[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!st[i]) {
prime[++cnt] = i;
phi[i] = i - 1;
}
for (int j = 1; prime[j] <= n / i; ++j) {
st[prime[j] * i] = true;
if (i % prime[j] == 0) {
phi[prime[j] * i] = prime[j] * phi[i];
break;
}
phi[prime[j] * i] = phi[i] * (prime[j] - 1);
}
}
}
扩展欧几里得
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
组合数
组合数
输出C(b,a)
C(b,a) -> C[a][b]
void init() {
for (int i = 0; i < N; ++i)
for (int j = 0; j <= i; ++j)
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
}
组合数II
求C(b,a)%mod
给定a,b。输出C(b,a)
1<=b<=a<=1e5
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010, mod = 1e9 + 7;
int fact[N], infact[N];
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int main()
{
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
int n;
scanf("%d", &n);
while (n -- )
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
}
return 0;
}
组合数III
求C(b,a)%mod
给定a,b,p,其中p是质数。输出C(b,a)%p
1<=n<=20, 1<=b<=a<=1e18, 1<=p<=1e5
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int C(int a, int b, int p)
{
if (b > a) return 0;
int res = 1;
for (int i = 1, j = a; i <= b; i ++, j -- )
{
res = (LL)res * j % p;
res = (LL)res * qmi(i, p - 2, p) % p;
}
return res;
}
int lucas(LL a, LL b, int p)
{
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
LL a, b;
int p;
cin >> a >> b >> p;
cout << lucas(a, b, p) << endl;
}
return 0;
}