数论知识点
网络赛数论板子题自闭
特此开坑
ACM数论知识点
参考博客
快速幂
ll qpow(int a,int p){
ll ans = 1;
while(p){
if(p & 1)ans = (ans * a) % mod;
a = (a * a) % mod;
p >>= 1;
}
return ans;
}
gcd
int gcd(int a,int b){
return a % b == 0 ? b : gcd(b, a % b);
}
整除分块
for(int l = 1,r = 0;l <= n;l = r + 1){
r = n/(n/l);
//...
}
1. 积性函数
如果已知一个函数为数论函数,且\(f(1)=1\),并且满足以下条件,若对于任意的两个互质的正整数\(p,q\)都满足\(f(p⋅q)=f(p)⋅f(q)\),那么则称这个函数为积性函数。
常见的积性函数
\(1. \mu(n)\)
莫比乌斯函数
$\mu(1) = 1 $
\(d=\Pi_{i=1}^{k}p_i\), 且 \(p_i\) 为互异素数时,\(\mu(d) = (-1)^k\)
\(d\) 含有任何质因子的幂次大于等于 \(2\) ,则 \(\mu(d) = 0\)
\(\mu * I = \epsilon\)
$2. \varphi(n) $
欧拉函数
表示 \([1,n)\) 内与 \(n\) 互质的数的个数
\(\varphi * I = id\)
\(\rightarrow \varphi * I * \mu = id * \mu\)
\(\rightarrow \varphi = id * \mu=\sum_{d|n}\mu(d)\cdot \dfrac n d\)
\[\frac{\varphi(n)}{n}=\sum_{d|n}\frac{\mu(d)}{d} \]
\(3. d(n)\)
约数个数
证明:
\(4. \sigma(n)\)
约数和函数
完全积性函数
\(1. \epsilon(n)\)
元函数, \(\epsilon(n) = [n==1]\)
\(f * \epsilon = f\)
\(2. I(n)\)
恒等函数, \(I(n) = 1\)
\(I * f = \sum_{d|n}f(d)\)
\(3. id(n)\)
单位函数, \(id(n) = n\)
\(lcy\) の \(ppt\)
2. 欧拉函数
欧拉函数\(\varphi(n)\)等于小于等于n的所有正整数中和n互素的数的个数
一些性质
性质一:
对于素数\(p\)
很显然,除了\(p\) 1到\(p-1\)和都\(p\)互素
性质二:
对于素数\(p\)
证明:
对于[1,\(p^k\)]中的数n,若与\(p^k\)不互素,则必有
而\(x\in[1,2,...,p^{k-1}]\)
所以\(\varphi(p^k) = p^k - p^{k-1}\)得证,第一个式子是总数,第二是不互素的数的个数
性质三:(积性)
对于素数\(p\),\(q\)
性质四: (计算公式)
对于任意正整数\(n\) 其中 \(n = \prod_{i=1}^{i = k}p_i^{e_i}\)
所以在欧拉筛中
if (i % prime[j] == 0) {//因数都一样,多乘了一个p phi[i * prime[j]] = phi[i] * prime[j]; break; } else {//积性 phi[i * phi[j]] = phi[i] * (phi[j] - 1); }
证明:
证毕
性质五:
若 \(i \ mod \ p = 0\)
则
若 \(i \ mod \ p \neq 0\)
则
这条性质显然,由积性直接得出(\(i\),\(p\)互质)
对于第一条性质,首先要知道一个引理:
证明:
若\(n+i\)与\(i\)有公因数\(k\),则\(n\)与\(i\)也有公因数\(k\),矛盾
由此
若\(gcd(a,b)=1\),则\(gcd(a,b+ka)=1\),\(k\in Z\)(\(k\)可以是负数)
因为\(i \ mod \ p = 0\),所以对于\(k\in[1,i]\),\(gcd(k,i)=1\)和\(gcd(k,i*p)\)是等价的
又\(gcd(k+xi,i)=1\),\(x\in[0,1,2,..,p-1]\)
对于\(k>i\)的\(k\)来说,一定是由\(k\in[1,i]\)转移而来
所以 \(\varphi(i*p)=p*\varphi(i)\)
欧拉定理:
若 \(gcd(a,n) == 1\) ,则
广义欧拉定理
一般用作降幂,也可以用来求逆元
\(\sum_{d|n} \varphi(d) = n\)
3. 莫比乌斯函数
先介绍莫比乌斯函数 \(\mu\) ,是一个常用的积性函数
一、性质
①、常用**
其中\([n=1]\)表示n == 1时候成立,为1,否则为0
也就是说任何大于1的整数n,其所有因子的莫比乌斯函数之和为0
②、
对于任意正整数n,
这个性质把莫比乌斯函数和欧拉函数联系在了一起
莫比乌斯反演
定理:
\(F(n)\) 和 \(f(n)\) 是定义在非负整数集合的两个函数,且满足
则有
利用卷积的性质不难整明
以及
4. 埃氏筛
bool isprime[maxn];
int prime[maxn],cnt;
void get(int N){
for(int i = 0;i <= N;i++)isprime[i] = true;
isprime[0] = isprime[1] = false;
for(int i = 2;i <= n;i++){
if(isprime[i]){
prime[++cnt] = i;
for(int j = i * i;j <= n;j += i){
isprime[j] = false;
}
}
}
}
5. 线性筛
基本思想:
对于每一个数n,筛去所有小于等于n最小质因数的质数和n乘积的数
我感觉线性筛其实是筛积性函数的通用的方法
直接给出代码
线性筛中最精华的部分就是这一句话
if(i % prime[j] == 0)break;
它确保了每个数只被它的最小质因数访问
例如 i = 2*3*5
, 则需要筛去 2*i
,不能筛去 3*i
观察 \(n=30\) , \(n\) 的因数有 \(2,3,5\) ,则只会被 \(15 * 2\) 筛去一次
而不能被 \(10 * 3\) 筛去。
$ n = p_1{k_1}p_2...p_n^{k_n}$
则 \(n\) 只会被 \(p_1^{k_1-1}p_2^{k_2}...p_n^{k_n}\) 筛去
void get_mu(int n){
mu[1] = 1;
for(int i = 2;i <= n;i++){
if(!vis[i]){
prime[++cnt] = i;
min_fac[i] = i;
}
for(int j = 1;j <= cnt && prime[j]*i <= n;j++){
vis[prime[j]*i] = 1;
if(i % prime[j] == 0)break;
min_fac[prime[j]*i] = prime[j];
}
}
}
线性筛还可以用来分解质因数
因为可以记录每个数的最小质因数。
void fac(int n){
while(n > 1){
p[min_fac[n]]++;
n /= min_fac[n];
}
}
6. 迪利克雷卷积
两个函数 \(f\) , \(g\) 的迪利克雷卷积
满足交换律,结合律,分配律,可以当作乘法
7. 莫比乌斯反演
若
则
另一种形式:
若
可以推出
8. 杜教筛
要求的东西 : \(\sum f(i)\)
设
记 \(S(n) = \sum_{i=1}^{n}f(i)\)
这一步的两个 \(\sum\) 的位置变换可以自己在纸上举了例子体会一下
9. min25筛
一种低于线性复杂度的求积性函数前缀和的筛法。
适用条件:
- \(f(p)\) 是多项式
- \(f(p^k)\) 便于计算
思想:
分为两个部分,第一部分是所有素数,第二部分是所有的合数
第一部分
搞来一个这样的函数 \(g(n,j)\)
所有的素数加上满足\(minp(i) > P_j\) 的所有 \(i\)
\([1-n]\) 中所有质数的 \(k\) 次方之和就是 \(g(n,x)\) ,\(P_x\) 是最后一个小于等于
\(\sqrt n\) 的质数
考虑 \(g(n,j)\) 的转移
这个东西自己在纸上写一些体会一下,注意 \(P_j\) 筛去的第一个数是 \(P_j^2\) , 第二个数不是 \(P_j^2+ P_j\)
第二部分
设
可以把 \(S(n,x)\) 也分成两部分,一部分是所有大于 \(P_x\) 的质数,另一部分是最小质因数大于 \(P_x\) 的合数,枚举最小质因子
当 \(e = 1\) 的时候, \(P_k\) 在前面枚举过了,不等于 \(1\) 时,需要加上 \(P_k^e\)
存下所有可能的 \(\lfloor\dfrac n x \rfloor\) , 做一个映射
要注意取模的时候不要爆数据范围
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7, inv6 = 166666668, inv2 = 500000004;
const int maxn = 1e6 + 10;
ll n, sqr;
ll prime[maxn], cnt, vis[maxn];
ll sp1[maxn], sp2[maxn];//sp1 p的前缀和,sp2 p^2的前缀和
ll w[maxn], tot;
ll g1[maxn], g2[maxn], ind1[maxn], ind2[maxn];
void get(int maxn) {
for (int i = 2; i <= maxn; i++) {
if (!vis[i]) {
prime[++cnt] = i;
sp1[cnt] = (sp1[cnt - 1] + i) % mod;
sp2[cnt] = (sp2[cnt - 1] + 1ll * i * i) % mod;
}
for (int j = 1; j <= cnt && prime[j] * i <= maxn; j++) {
vis[prime[j] * i] = 1;
if (i % prime[j] == 0)break;
}
}
}
ll S(ll x, int y){
if (prime[y] >= x)return 0;
ll k = x <= sqr ? ind1[x] : ind2[n / x];
ll ans = (g2[k] - g1[k] + mod - (sp2[y] - sp1[y]) + mod) % mod;
for (int i = y + 1; i <= cnt && prime[i] * prime[i] <= x; i++)
{
ll pe = prime[i];
for (int e = 1; pe <= x; e++, pe = pe * prime[i])
{
ll xx = pe % mod;
ans = (ans + xx * (xx - 1) % mod * (S(x / pe, i) + (e != 1))) % mod;
}
}
return ans % mod;
}
int main() {
scanf("%lld", &n);
sqr = sqrt(n);
get(sqr);
for (ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
w[++tot] = n / l;
ll k = w[tot] % mod;
g1[tot] = (k * (k + 1) % mod * inv2 - 1 + mod) % mod;
g2[tot] = (k * (k + 1) % mod * (2 * k + 1) %mod * inv6 % mod + mod - 1) % mod;
if (w[tot] <= sqr)ind1[n / l] = tot;
else ind2[n / (n / l)] = tot;
}
for (int i = 1; i <= cnt; i++) {
//g(n,j) 滚第一维
for (int j = 1; j <= tot && prime[i] * prime[i] <= w[j]; j++) {
ll k = w[j] / prime[i] <= sqr ? ind1[w[j] / prime[i]] : ind2[n / (w[j] / prime[i])];
g1[j] -= prime[i] * (g1[k] - sp1[i - 1] + mod) % mod;
g2[j] -= prime[i] * prime[i] % mod * (g2[k] - sp2[i - 1] + mod) % mod;
g1[j] %= mod; g2[j] %= mod;
if (g1[j] < 0)g1[j] += mod;
if (g2[j] < 0)g2[j] += mod;
}
}
printf("%lld\n", (S(n, 0) + 1) % mod); //f(1) = 1
}