数论知识总结
分类:筛素数(埃氏筛法、线性筛法、二次筛法)、分解质因数、快速幂、约数个数、欧拉函数、同余、矩阵乘法、组合计数、高斯消元、容斥原理、概率与数学期望、博弈论
筛素数方法
埃氏筛法: l o g l o g ( n ) loglog(n) loglog(n),素数所有的倍数直接筛掉,线性筛法: O ( n ) O(n) O(n),不断素数倍数筛掉,二次筛法间接地把某一段很大的区间素数筛掉(线性筛法时间复杂度较高的情况)
注意的是,1有的时候需要特判,联系图论一起考察
1292. 哥德巴赫猜想
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
bool st[N];
int primes[N], cnt;
int n;
void init(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] * i <= n; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main()
{
init(N - 1);
while (cin >> n, n)
{
for (int i = 0; ; i ++ )
{
int a = primes[i], b = n - a;
if (!st[b])
{
printf("%d = %d + %d\n", n, a, b);
break;
}
}
}
return 0;
}
1293. 夏洛克和他的女朋友
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int primes[N], cnt;
bool st[N];
int n;
void init(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] * i <= n; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main()
{
cin >> n;
init(n + 1);
if (n <= 2) puts("1");
else puts("2");
for (int i = 2; i <= n + 1; i ++ )
if (!st[i]) printf("1 ");
else printf("2 ");
return 0;
}
AcWing 196. 质数距离
#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long LL;
using namespace std;
const int N = 1000010;
int primes[N], cnt;
bool st[N];
int l, r;
void init(int n)
{
memset(st, 0, sizeof st);
cnt = 0;
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] * i <= n; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main()
{
while (cin >> l >> r)
{
init(50010);
memset(st, 0, sizeof st);
for (int i = 0; i < cnt; i ++ )
{
LL p = primes[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)
primes[cnt ++ ] = i + l;
}
if (cnt < 2) puts("There are no adjacent primes.");
else
{
int minp = 0, maxp = 0;
for (int i = 0; i + 1 < cnt; i ++ )
{
int d = primes[i + 1] - primes[i];
if (d < primes[minp + 1] - primes[minp]) minp = i;
if (d > primes[maxp + 1] - primes[maxp]) maxp = i;
}
printf("%d,%d are closest, %d,%d are most distant.\n",
primes[minp], primes[minp + 1],
primes[maxp], primes[maxp + 1]);
}
}
return 0;
}
分解质因数
197. 阶乘分解
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000010;
int primes[N], cnt;
bool st[N];
int n;
void init(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] * i <= n; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main()
{
cin >> n;
init(n);
for (int i = 0; i < cnt; i ++ )
{
int p = primes[i];
int s = 0;
for (int j = n; j; j /= p) s += j / p;
printf("%d %d\n", p, s);
}
return 0;
}
序列的第k个数
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 200907;
typedef long long LL;
LL qmi(int a, int k)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % mod;
a = (LL)a * a % mod;
k >>= 1;
}
return res;
}
int main()
{
int T;
cin >> T;
while (T -- )
{
int a, b, c, k;
cin >> a >> b >> c >> k;
if (2 * b == a + c) cout << (a + (b - a) * (LL)(k - 1)) % mod << endl;
else cout << (LL)a * qmi(b / a, k - 1) % mod << endl;
}
return 0;
}
1290. 越狱
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int mod = 100003;
int qmi(int a, LL k)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % mod;
a = (LL)a * a % mod;
k >>= 1;
}
return res;
}
int main()
{
int m;
LL n;
cin >> m >> n;
cout << (qmi(m, n) - (LL)m * qmi(m - 1, n - 1) % mod + mod) % mod << endl;
return 0;
}