下面这个博客里有一些神奇的模板: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() { }