数论模板
下面这个博客里有一些神奇的模板:http://blog.sina.com.cn/s/blog_82462ac30100y17u.html
里面包含了线性的数论算法,可以在线性的时间内实现:
1.筛出素数
2.求出每个数包含的素数个数
3.求出每个数的因子个数
4.求出欧拉函数
5.求出约数和
我对数论的理解就只能理解到线性素数筛,但感觉那个素数筛要比自己平时写的短而且快太多了,在此存一下模板,方便以后打印,代码都是源自上面的博客的。
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
#define maxn 100000
#define ll long long
int p[maxn + 50]; // 存的素数表
int tot;
int vis[maxn + 50]; // vis访问表
// 线性素数筛
void getPrime()
{
memset(vis, 0, sizeof(vis));
tot = 0;
for (int i = 2; i <= maxn; i++){
if (!vis[i]) p[tot++] = i;
for (int j = 0; j < tot&&i*p[j] <= maxn; j++){
vis[i*p[j]] = true;
if (!(i%p[j])) break;
}
}
}
int cnt[maxn + 50];
// 获得每个数包含的素数因子
void getPrime2()
{
memset(vis, 0, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
tot = 0;
for (int i = 2; i <= maxn; i++){
if (!vis[i]) {
p[tot++] = i;
cnt[i] = 1;
}
for (int j = 0; j < tot&&i*p[j] <= maxn; j++){
vis[i*p[j]] = true;
cnt[i*p[j]] = cnt[i] + 1;
if (!(i%p[j])) break;
}
}
}
int divv[maxn + 50];
// 线性求每个数包含的因子个数
void getPrime3()
{
memset(vis, 0, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
memset(divv, 0, sizeof(divv));
tot = 0;
// if we consider divv[1]=1,then it should be added
// divv[1]=1
for (int i = 2; i <= maxn; i++){
if (!vis[i]) {
p[tot++] = i;
cnt[i] = 1;
divv[i] = 2;
}
for (int j = 0; j < tot&&i*p[j] <= maxn; j++){
vis[i*p[j]] = true;
if (i%p[j] == 0){
divv[i*p[j]] = divv[i] / (cnt[i] + 1)*(cnt[i] + 2);
cnt[i*p[j]] = cnt[i] + 1;
break;
}
else{
cnt[i*p[j]] = 1;
divv[i*p[j]] = divv[i] * divv[p[j]];
}
}
}
}
int phi[maxn + 50];
void getPrime4()
{
memset(phi, 0, sizeof(phi));
memset(vis, 0, sizeof(vis));
tot = 0;
for (int i = 2; i <= maxn; i++){
if (!vis[i]){
p[tot++] = i;
phi[i] = i - 1;
}
for (int j = 0; j < tot&&i*p[j] <= maxn; j++){
vis[i*p[j]] = true;
if (i%p[j] == 0){
phi[i*p[j]] = phi[i] * p[j];
break;
}
else phi[i*p[j]] = phi[i] * (p[j] - 1);
}
}
}
int mnp[maxn + 50]; // minimal prime factor
ll dsum[maxn + 50]; // divisor sum
// 求约数和dsum
void getPrime5()
{
memset(vis, 0, sizeof(vis));
tot = 0;
for (int i = 2; i <= maxn; i++){
if (!vis[i]) {
p[tot++] = i;
mnp[i] = i;
}
for (int j = 0; j < tot&&i*p[j] <= maxn; j++){
vis[i*p[j]] = true;
mnp[i*p[j]] = p[j];
if (!(i%p[j])) break;
}
}
// i=p1^a1*p2^a2...pn^an
// dsum[i]=(1+p1+..p1^a1)*(1+p2+..p2^a2).....
dsum[1] = 1; int t0;
for (int i = 2; i <= maxn; i++){
t0 = 1;
for (int j = i; j%mnp[i] == 0; j /= mnp[i]) t0 *= mnp[i];
if (i != t0) dsum[i] = dsum[t0] * dsum[i / t0];
else dsum[i] = (1LL * t0*mnp[i] - 1) / (mnp[i] - 1);
}
}
int main()
{
}
浙公网安备 33010602011771号